diff options
Diffstat (limited to '')
34 files changed, 12779 insertions, 0 deletions
diff --git a/python/acquire-item.cc b/python/acquire-item.cc new file mode 100644 index 0000000..af79fd9 --- /dev/null +++ b/python/acquire-item.cc @@ -0,0 +1,356 @@ +/* + * acquire-item.cc - Wrapper around pkgAcquire::Item and pkgAcqFile. + * + * Copyright 2004-2009 Canonical Ltd. + * Copyright 2009 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 "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/acquire-item.h> +#include <map> + +using namespace std; + +inline pkgAcquire::Item *acquireitem_tocpp(PyObject *self) +{ + pkgAcquire::Item *itm = GetCpp<pkgAcquire::Item*>(self); + if (itm == 0) + PyErr_SetString(PyExc_ValueError, "Acquire() has been shut down or " + "the AcquireFile() object has been deallocated."); + return itm; +} + +static PyObject *acquireitem_get_complete(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? PyBool_FromLong(item->Complete) : 0; +} + +static PyObject *acquireitem_get_desc_uri(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? CppPyString(item->DescURI()) : 0; +} + +static PyObject *acquireitem_get_destfile(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? CppPyPath(item->DestFile) : 0; +} + + +static PyObject *acquireitem_get_error_text(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? CppPyString(item->ErrorText) : 0; +} + +static PyObject *acquireitem_get_filesize(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? MkPyNumber(item->FileSize) : 0; +} + +static PyObject *acquireitem_get_id(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? MkPyNumber(item->ID) : 0; +} + +static PyObject *acquireitem_get_active_subprocess(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); +#if APT_PKG_MAJOR >= 5 + return item ? Py_BuildValue("s", item->ActiveSubprocess.c_str()) : 0; +#else + return item ? Py_BuildValue("s", item->Mode) : 0; +#endif +} + +static PyObject *acquireitem_get_mode(PyObject *self, void *closure) +{ + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "AcquireItem.mode is deprecated, use AcquireItem.active_subprocess instead.", 1) == -1) + return NULL; + return acquireitem_get_active_subprocess(self, closure); +} + +static PyObject *acquireitem_get_is_trusted(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? PyBool_FromLong(item->IsTrusted()) : 0; +} + +static PyObject *acquireitem_get_local(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? PyBool_FromLong(item->Local) : 0; +} + +static PyObject *acquireitem_get_partialsize(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? MkPyNumber(item->PartialSize) : 0; +} + +static PyObject *acquireitem_get_status(PyObject *self, void *closure) +{ + pkgAcquire::Item *item = acquireitem_tocpp(self); + return item ? MkPyNumber(item->Status) : 0; +} + +static int acquireitem_set_id(PyObject *self, PyObject *value, void *closure) +{ + pkgAcquire::Item *Itm = acquireitem_tocpp(self); + if (Itm == 0) + return -1; + if (PyLong_Check(value)) { + Itm->ID = PyLong_AsUnsignedLong(value); + } + else if (PyInt_Check(value)) { + Itm->ID = PyInt_AsLong(value); + } + else { + PyErr_SetString(PyExc_TypeError, "value must be integer."); + return -1; + } + return 0; +} + + +static PyGetSetDef acquireitem_getset[] = { + {"complete",acquireitem_get_complete,0, + "A boolean value determining whether the item has been fetched\n" + "completely"}, + {"desc_uri",acquireitem_get_desc_uri,NULL, + "A string describing the URI from which the item is acquired."}, + {"destfile",acquireitem_get_destfile,NULL, + "The path to the file where the item will be stored."}, + {"error_text",acquireitem_get_error_text,NULL, + "If an error occurred, a string describing the error; empty string\n" + "otherwise."}, + {"filesize",acquireitem_get_filesize,NULL, + "The size of the file (number of bytes). If unknown, it is set to 0."}, + {"id",acquireitem_get_id,acquireitem_set_id, + "The ID of the item. An integer which can be set by progress classes."}, + {"mode",acquireitem_get_mode,NULL, + "Old name for active_subprocess"}, + {"active_subprocess",acquireitem_get_active_subprocess,NULL, + "The name of the active subprocess (for instance, 'gzip', 'rred' or 'gpgv')."}, + {"is_trusted",acquireitem_get_is_trusted,NULL, + "Whether the item is trusted or not. Only True for packages\n" + "which come from a repository signed with one of the keys in\n" + "APT's keyring."}, + {"local",acquireitem_get_local,NULL, + "Whether we are fetching a local item (copy:/) or not."}, + {"partialsize",acquireitem_get_partialsize,NULL, + "The amount of data which has already been fetched (number of bytes)."}, + {"status",acquireitem_get_status,NULL, + "An integer representing the item's status which can be compared\n" + "against one of the STAT_* constants defined in this class."}, + {} +}; + +static PyObject *acquireitem_repr(PyObject *Self) +{ + pkgAcquire::Item *Itm = acquireitem_tocpp(Self); + if (Itm == 0) + return 0; + + string repr; + strprintf(repr, "<%s object:" + "Status: %i Complete: %i Local: %i IsTrusted: %i " + "FileSize: %llu DestFile:'%s' " + "DescURI: '%s' ID:%lu ErrorText: '%s'>", + Self->ob_type->tp_name, + Itm->Status, Itm->Complete, Itm->Local, Itm->IsTrusted(), + Itm->FileSize, Itm->DestFile.c_str(), Itm->DescURI().c_str(), + Itm->ID,Itm->ErrorText.c_str()); + // Use CppPyPath here, the string may contain a path, so we should + // decode it like one. + return CppPyPath(repr); +} + +static void acquireitem_dealloc(PyObject *self) +{ + CppDeallocPtr<pkgAcquire::Item*>(self); +} + +static const char *acquireitem_doc = + "Represent a single item to be fetched by an Acquire object.\n\n" + "It is not possible to construct instances of this class directly.\n" + "Prospective users should construct instances of a subclass such as\n" + "AcquireFile instead. It is not possible to create subclasses on the\n" + "Python level, only on the C++ level."; +PyTypeObject PyAcquireItem_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.AcquireItem", // tp_name + sizeof(CppPyObject<pkgAcquire::Item*>), // tp_basicsize + 0, // tp_itemsize + // Methods + acquireitem_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + acquireitem_repr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC, // tp_flags + acquireitem_doc, // tp_doc + CppTraverse<pkgAcquire::Item*>, // tp_traverse + CppClear<pkgAcquire::Item*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + acquireitem_getset, // tp_getset +}; + +static PyObject *acquirefile_new(PyTypeObject *type, PyObject *Args, PyObject * kwds) +{ + PyObject *pyfetcher; + PyObject *pyhashes = nullptr; + HashStringList hashes; + const char *uri, *descr, *shortDescr; + PyApt_Filename destDir, destFile; + unsigned long long size = 0; + uri = descr = shortDescr = destDir = destFile = ""; + + char *kwlist[] = {"owner", "uri", "hash", "size", "descr", "short_descr", + "destdir", "destfile", NULL + }; +#if PY_MAJOR_VERSION >= 3 + const char *fmt = "O!s|OKssO&O&"; +#else + // no "$" support to indicate that the remaining args are keyword only + // in py2.x :/ + const char *fmt = "O!s|OKssO&O&"; +#endif + if (PyArg_ParseTupleAndKeywords(Args, kwds, fmt, kwlist, + &PyAcquire_Type, &pyfetcher, &uri, + &pyhashes, + &size, &descr, &shortDescr, + PyApt_Filename::Converter, &destDir, + PyApt_Filename::Converter, &destFile) == 0) + return 0; + + if (pyhashes == nullptr) + ; + else if (PyString_Check(pyhashes)) + hashes = HashStringList(PyString_AsString(pyhashes)); + else if (PyObject_TypeCheck(pyhashes, &PyHashStringList_Type)) + hashes = GetCpp <HashStringList>(pyhashes); + else + return PyErr_SetString(PyExc_TypeError, "'hash' value must be an apt_pkg.HashStringList or a string"), nullptr; + + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(pyfetcher); + pkgAcqFile *af = new pkgAcqFile(fetcher, // owner + uri, // uri + hashes, // hash + size, // size + descr, // descr + shortDescr, + destDir, + destFile); // short-desc + CppPyObject<pkgAcqFile*> *AcqFileObj = CppPyObject_NEW<pkgAcqFile*>(pyfetcher, type); + AcqFileObj->Object = af; + return AcqFileObj; +} + + +static char *acquirefile_doc = + "AcquireFile(owner, uri[, hash: Union[apt_pkg.HashStringList, str], size, descr, short_descr, destdir," + "destfile])\n\n" + "Represent a file to be fetched. The parameter 'owner' points to\n" + "an apt_pkg.Acquire object and the parameter 'uri' to the source\n" + "location. Normally, the file will be stored in the current directory\n" + "using the file name given in the URI. This directory can be changed\n" + "by passing the name of a directory to the 'destdir' parameter. It is\n" + "also possible to set a path to a file using the 'destfile' parameter,\n" + "but both cannot be specified together.\n" + "\n" + "The parameters 'short_descr' and 'descr' can be used to specify\n" + "a short description and a longer description for the item. This\n" + "information is used by progress classes to refer to the item and\n" + "should be short, for example, package name as 'short_descr' and\n" + "and something like 'http://localhost sid/main python-apt 0.7.94.2'\n" + "as 'descr'." + "\n" + "The parameters 'hash' and 'size' are used to verify the resulting\n" + "file. The parameter 'size' is also to calculate the total amount\n" + "of data to be fetched and is useful for resuming a interrupted\n" + "download.\n\n" + "All parameters can be given by name (i.e. as keyword arguments)."; + +PyTypeObject PyAcquireFile_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.AcquireFile", // tp_name + sizeof(CppPyObject<pkgAcqFile*>),// tp_basicsize + 0, // tp_itemsize + // Methods + acquireitem_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + acquirefile_doc, // tp_doc + CppTraverse<pkgAcqFile*>, // tp_traverse + CppClear<pkgAcqFile*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyAcquireItem_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + acquirefile_new, // tp_new +}; + diff --git a/python/acquire.cc b/python/acquire.cc new file mode 100644 index 0000000..aab899f --- /dev/null +++ b/python/acquire.cc @@ -0,0 +1,424 @@ +/* acquire.cc - Wrapper for pkgAcquire. + * + * Copyright 2004-2009 Canonical Ltd + * Copyright 2009 Julian Andres Klode <jak@debian.org> + * + * Authors: Michael Vogt + * Julian Andres Klode + * + * 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 "generic.h" +#include "apt_pkgmodule.h" +#include "progress.h" + +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire-worker.h> + + +static PyObject *acquireworker_get_current_item(PyObject *self, void *closure) +{ + pkgAcquire::Worker *worker = GetCpp<pkgAcquire::Worker*>(self); + pkgAcquire::ItemDesc *desc = worker->CurrentItem; + if (desc == NULL) { + Py_RETURN_NONE; + } + PyObject *PyAcq = GetOwner<pkgAcquire::Worker*>(self); + PyObject *PyItem = PyAcquireItem_FromCpp(desc->Owner, false, PyAcq); + PyObject *PyDesc = PyAcquireItemDesc_FromCpp(desc, false, PyItem); + Py_XDECREF(PyItem); + return PyDesc; +} + +static PyObject *acquireworker_get_status(PyObject *self, void *closure) +{ + return CppPyString(GetCpp<pkgAcquire::Worker*>(self)->Status); +} + +static PyObject *acquireworker_get_current_size(PyObject *self, void *closure) +{ + if (GetCpp<pkgAcquire::Worker*>(self)->CurrentItem == nullptr) + return 0; + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->CurrentItem->CurrentSize); +} + +static PyObject *acquireworker_get_total_size(PyObject *self, void *closure) +{ + if (GetCpp<pkgAcquire::Worker*>(self)->CurrentItem == nullptr) + return 0; + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->CurrentItem->TotalSize); +} + +static PyObject *acquireworker_get_resumepoint(PyObject *self, void *closure) +{ + if (GetCpp<pkgAcquire::Worker*>(self)->CurrentItem == nullptr) + return 0; + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->CurrentItem->ResumePoint); +} + +static PyGetSetDef acquireworker_getset[] = { + {"current_item",acquireworker_get_current_item,0, + "The item currently being fetched, as an apt_pkg.AcquireItemDesc object."}, + {"status",acquireworker_get_status,0, + "The status of the worker, as a string."}, + {"current_size",acquireworker_get_current_size,0, + "The amount of data fetched so far for the current item."}, + {"total_size",acquireworker_get_total_size,0, + "The total size of the item."}, + {"resumepoint",acquireworker_get_resumepoint,0, + "The amount of data which was already available when the download was\n" + "started."}, + {NULL} +}; + +static const char *acquireworker_doc = + "Represent a sub-process responsible for fetching files from\n" + "remote locations. This sub-process uses 'methods' located in\n" + "the directory specified by the configuration option\n" + "Dir::Bin::Methods."; +PyTypeObject PyAcquireWorker_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.AcquireWorker", // tp_name + sizeof(CppPyObject<pkgAcquire::Worker*>),// tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgAcquire::Worker*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + acquireworker_doc, // tp_doc + CppTraverse<pkgAcquire::Worker*>, // tp_traverse + CppClear<pkgAcquire::Worker*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + acquireworker_getset, // tp_getset +}; + + +static pkgAcquire::ItemDesc* acquireitemdesc_tocpp(PyObject *self) { + pkgAcquire::ItemDesc *item = GetCpp<pkgAcquire::ItemDesc*>(self); + if (item == NULL) + PyErr_SetString(PyExc_ValueError, "Acquire has been shutdown"); + return item; +} + +static PyObject *acquireitemdesc_get_uri(PyObject *self, void *closure) +{ + pkgAcquire::ItemDesc *item = acquireitemdesc_tocpp(self); + return item ? CppPyString(item->URI) : NULL; +} +static PyObject *acquireitemdesc_get_description(PyObject *self, void *closure) +{ + pkgAcquire::ItemDesc *item = acquireitemdesc_tocpp(self); + return item ? CppPyString(item->Description) : NULL; +} +static PyObject *acquireitemdesc_get_shortdesc(PyObject *self, void *closure) +{ + pkgAcquire::ItemDesc *item = acquireitemdesc_tocpp(self); + return item ? CppPyString(item->ShortDesc) : NULL; +} +static PyObject *acquireitemdesc_get_owner(CppPyObject<pkgAcquire::ItemDesc*> *self, void *closure) +{ + if (self->Owner != NULL) { + Py_INCREF(self->Owner); + return self->Owner; + } + else if (self->Object) { + self->Owner = PyAcquireItem_FromCpp(self->Object->Owner, false, NULL); + Py_INCREF(self->Owner); + return self->Owner; + } + Py_RETURN_NONE; +} + +static PyGetSetDef acquireitemdesc_getset[] = { + {"uri",acquireitemdesc_get_uri,0, + "The URI from which this item would be downloaded."}, + {"description",acquireitemdesc_get_description,0, + "A string describing the item."}, + {"shortdesc",acquireitemdesc_get_shortdesc,0, + "A short string describing the item (e.g. package name)."}, + {"owner",(getter)acquireitemdesc_get_owner,0, + "The owner of the item, an apt_pkg.AcquireItem object."}, + {NULL} +}; + +static char *acquireitemdesc_doc = + "Provide the description of an item and the URI the item is\n" + "fetched from. Progress classes make use of such objects to\n" + "retrieve description and other information about an item."; +PyTypeObject PyAcquireItemDesc_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.AcquireItemDesc", // tp_name + sizeof(CppPyObject<pkgAcquire::ItemDesc*>),// tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgAcquire::ItemDesc*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC), + acquireitemdesc_doc, // tp_doc + CppTraverse<pkgAcquire::ItemDesc*>,// tp_traverse + CppClear<pkgAcquire::ItemDesc*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + acquireitemdesc_getset, // 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 + 0, // tp_new +}; + +static PyObject *PkgAcquireRun(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + + int pulseInterval = 500000; + if (PyArg_ParseTuple(Args, "|i", &pulseInterval) == 0) + return 0; + + pkgAcquire::RunResult run = fetcher->Run(pulseInterval); + + return HandleErrors(MkPyNumber(run)); +} + + +static PyObject *PkgAcquireShutdown(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + if (PyArg_ParseTuple(Args, "") == 0) + return 0; + fetcher->Shutdown(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgAcquireGetLock(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + PyApt_Filename path; + if (PyArg_ParseTuple(Args, "O&", PyApt_Filename::Converter, &path) == 0) + return 0; + fetcher->GetLock(path); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + + + +static PyMethodDef PkgAcquireMethods[] = { + {"run",PkgAcquireRun,METH_VARARGS, + "run() -> int\n\nRun the fetcher and return one of RESULT_CANCELLED,\n" + "RESULT_CONTINUE, RESULT_FAILED.\n\n" + "RESULT_CONTINUE means that all items which where queued prior to\n" + "calling run() have been fetched successfully or failed transiently.\n\n" + "RESULT_CANCELLED means canceled by the progress class.\n\n" + "RESULT_FAILED means a generic failure."}, + {"shutdown",PkgAcquireShutdown, METH_VARARGS, + "shutdown()\n\n" + "Shut the fetcher down, removing all items from it. Future access to\n" + "queued AcquireItem objects will cause a segfault. The partial result\n" + "is kept on the disk and not removed and APT might reuse it."}, + {"get_lock",PkgAcquireGetLock, METH_VARARGS, + "get_lock(log: str)\n\n" + "Acquires a log for the given directory, using a file 'lock' in it."}, + {} +}; + +#define fetcher (GetCpp<pkgAcquire*>(Self)) +static PyObject *PkgAcquireGetTotalNeeded(PyObject *Self,void*) +{ + return MkPyNumber(fetcher->TotalNeeded()); +} +static PyObject *PkgAcquireGetFetchNeeded(PyObject *Self,void*) +{ + return MkPyNumber(fetcher->FetchNeeded()); +} +static PyObject *PkgAcquireGetPartialPresent(PyObject *Self,void*) +{ + return MkPyNumber(fetcher->PartialPresent()); +} +#undef fetcher + +static PyObject *PkgAcquireGetWorkers(PyObject *self, void *closure) +{ + PyObject *List = PyList_New(0); + pkgAcquire *Owner = GetCpp<pkgAcquire*>(self); + PyObject *PyWorker = NULL; + for (pkgAcquire::Worker *Worker = Owner->WorkersBegin(); + Worker != 0; Worker = Owner->WorkerStep(Worker)) { + PyWorker = PyAcquireWorker_FromCpp(Worker, false, self); + PyList_Append(List, PyWorker); + Py_DECREF(PyWorker); + } + return List; +} +static PyObject *PkgAcquireGetItems(PyObject *Self,void*) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + PyObject *List = PyList_New(0); + PyObject *Obj; + for (pkgAcquire::ItemIterator I = fetcher->ItemsBegin(); + I != fetcher->ItemsEnd(); I++) { + Obj = PyAcquireItem_FromCpp(*I, false, Self); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyGetSetDef PkgAcquireGetSet[] = { + {"fetch_needed",PkgAcquireGetFetchNeeded,0, + "The total amount of data to be fetched (number of bytes)."}, + {"items",PkgAcquireGetItems,0, + "A list of all items as apt_pkg.AcquireItem objects, including already\n" + "fetched ones and to be fetched ones."}, + {"workers",PkgAcquireGetWorkers,0, + "A list of all active workers as apt_pkg.AcquireWorker objects."}, + {"partial_present",PkgAcquireGetPartialPresent,0, + "The amount of data which is already available (number of bytes)."}, + {"total_needed",PkgAcquireGetTotalNeeded,0, + "The amount of data that needs to fetched plus the amount of data\n" + "which has already been fetched (number of bytes)."}, + {} +}; + +static PyObject *PkgAcquireNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + pkgAcquire *fetcher; + + PyObject *pyFetchProgressInst = NULL; + char *kwlist[] = {"progress", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"|O",kwlist,&pyFetchProgressInst) == 0) + return 0; + + PyFetchProgress *progress = 0; + if (pyFetchProgressInst != NULL) { + // FIXME: memleak? + progress = new PyFetchProgress(); + progress->setCallbackInst(pyFetchProgressInst); + } + + fetcher = new pkgAcquire(); + fetcher->SetLog(progress); + + PyObject *FetcherObj = CppPyObject_NEW<pkgAcquire*>(NULL, type, fetcher); + + if (progress != 0) + progress->setPyAcquire(FetcherObj); + // prepare our map of items. + return HandleErrors(FetcherObj); +} + +/** + * Create a new apt_pkg.Acquire Python object from the pkgAcquire object. + */ +PyObject *PyAcquire_FromCpp(pkgAcquire *fetcher, bool Delete, PyObject *owner) { + CppPyObject<pkgAcquire*> *obj = CppPyObject_NEW<pkgAcquire*>(owner, &PyAcquire_Type, fetcher); + obj->NoDelete = (!Delete); + return obj; +} + +static char *doc_PkgAcquire = + "Acquire([progress: apt.progress.base.AcquireProgress])\n\n" + "Coordinate the retrieval of files via network or local file system\n" + "(using 'copy:/path/to/file' style URIs). The optional argument\n" + "'progress' takes an apt.progress.base.AcquireProgress object\n" + "which may report progress information."; + +PyTypeObject PyAcquire_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Acquire", // tp_name + sizeof(CppPyObject<pkgAcquire*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgAcquire*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + doc_PkgAcquire, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgAcquireMethods, // tp_methods + 0, // tp_members + PkgAcquireGetSet, // 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 + PkgAcquireNew, // tp_new +}; + + diff --git a/python/apt_instmodule.cc b/python/apt_instmodule.cc new file mode 100644 index 0000000..eb01074 --- /dev/null +++ b/python/apt_instmodule.cc @@ -0,0 +1,87 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_instmodule.cc,v 1.3 2002/01/08 06:53:04 jgg Exp $ +/* ###################################################################### + + apt_intmodule - Top level for the python module. Create the internal + structures for the module in the interpriter. + + Note, this module shares state (particularly global config) with the + apt_pkg module. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "apt_instmodule.h" +#include "generic.h" + +#include <apt-pkg/debfile.h> +#include <apt-pkg/error.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <Python.h> + /*}}}*/ + +PyObject *PyAptError; +PyObject *PyAptWarning; +static PyMethodDef *methods = 0; + + +static const char *apt_inst_doc = + "Functions for working with ar/tar archives and .deb packages.\n\n" + "This module provides useful classes and functions to work with\n" + "archives, modelled after the 'TarFile' class in the 'tarfile' module."; +#define ADDTYPE(mod,name,type) { \ + if (PyType_Ready(type) == -1) RETURN(0); \ + Py_INCREF(type); \ + PyModule_AddObject(mod,name,(PyObject *)type); } + + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "apt_inst", + apt_inst_doc, + -1, + methods, + 0, + 0, + 0, + 0 +}; +#define RETURN(x) return x +#define INIT_ERROR return 0 +extern "C" PyObject * PyInit_apt_inst() +#else +#define INIT_ERROR return +extern "C" void initapt_inst() +#define RETURN(x) return +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule3("apt_inst",methods, apt_inst_doc); +#endif + + PyObject *apt_pkg = PyImport_ImportModule("apt_pkg"); + if (apt_pkg == NULL) + INIT_ERROR; + PyAptError = PyObject_GetAttrString(apt_pkg, "Error"); + if (PyAptError == NULL) + INIT_ERROR; + PyAptWarning = PyObject_GetAttrString(apt_pkg, "Warning"); + if (PyAptWarning == NULL) + INIT_ERROR; + + PyModule_AddObject(module,"Error",PyAptError); + PyModule_AddObject(module,"Warning",PyAptWarning); + ADDTYPE(module,"ArMember",&PyArMember_Type); + ADDTYPE(module,"ArArchive",&PyArArchive_Type); + ADDTYPE(module,"DebFile",&PyDebFile_Type); + ADDTYPE(module,"TarFile",&PyTarFile_Type); + ADDTYPE(module,"TarMember",&PyTarMember_Type); + ADDTYPE(module,"__FileFd",&PyFileFd_Type); + RETURN(module); +} diff --git a/python/apt_instmodule.h b/python/apt_instmodule.h new file mode 100644 index 0000000..92c9800 --- /dev/null +++ b/python/apt_instmodule.h @@ -0,0 +1,29 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_instmodule.h,v 1.2 2002/01/08 06:53:04 jgg Exp $ +/* ###################################################################### + + Prototypes for the module + + ##################################################################### */ + /*}}}*/ +#ifndef APT_INSTMODULE_H +#define APT_INSTMODULE_H + +#include <Python.h> +#include "generic.h" +#include <apt-pkg/extracttar.h> + + +extern PyTypeObject PyArMember_Type; +extern PyTypeObject PyArArchive_Type; +extern PyTypeObject PyDebFile_Type; +extern PyTypeObject PyTarFile_Type; +extern PyTypeObject PyTarMember_Type; +extern PyTypeObject PyFileFd_Type; +struct PyTarFileObject : public CppPyObject<ExtractTar*> { + int min; + FileFd Fd; +}; + +#endif diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc new file mode 100644 index 0000000..84b1e92 --- /dev/null +++ b/python/apt_pkgmodule.cc @@ -0,0 +1,1117 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_pkgmodule.cc,v 1.5 2003/07/23 02:20:24 mdz Exp $ +/* ###################################################################### + + apt_pkgmodule - Top level for the python module. Create the internal + structures for the module in the interpriter. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "apt_pkgmodule.h" +#include "generic.h" + +#include <apt-pkg/configuration.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/version.h> +#include <apt-pkg/deblistparser.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/hashes.h> +#include <apt-pkg/init.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/orderlist.h> +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/gpgv.h> + +#include <sys/stat.h> +#include <libintl.h> +#include <unistd.h> +#include <Python.h> + /*}}}*/ + +static char PyAptError_Doc[] = + "Exception class for most python-apt exceptions.\n" + "\n" + "This class replaces the use of :class:`SystemError` in previous versions\n" + "of python-apt. It inherits from :class:`SystemError`, so make sure to\n" + "catch this class first.\n\n" + ".. versionadded:: 1.1"; + +PyObject *PyAptError; + +static char PyAptWarning_Doc[] = + "Exception class for most python-apt warnings.\n" + "\n" + ".. versionadded:: 2.7"; + +PyObject *PyAptWarning; + +static char PyAptCacheMismatchError_Doc[] = + "Raised when passing an object from a different cache to\n" + ":class:`apt_pkg.DepCache` methods\n\n" + ".. versionadded:: 1.6.1"; + +PyObject *PyAptCacheMismatchError; + +/** + * A Python->C->Python gettext() function. + * + * Python's gettext() ignores setlocale() which causes a strange behavior + * because the values received from apt-pkg respect setlocale(). We circumvent + * this problem by calling the C version of gettext(). This is also much + * faster. + */ +static PyObject *py_gettext(PyObject *self, PyObject *Args) { + const char *msg; + char *domain = "python-apt"; + if (PyArg_ParseTuple(Args,"s|s:gettext",&msg, &domain) == 0) + return 0; + + return CppPyString(dgettext(domain, msg)); +} + +// newConfiguration - Build a new configuration class /*{{{*/ +// --------------------------------------------------------------------- + /*}}}*/ + +// Version Wrappers /*{{{*/ +// These are kind of legacy.. +static char *doc_VersionCompare = + "version_compare(a: str, b: str) -> int\n\n" + "Compare the given versions; return a strictly negative value if 'a' is \n" + "smaller than 'b', 0 if they are equal, and a strictly positive value if\n" + "'a' is larger than 'b'."; +static PyObject *VersionCompare(PyObject *Self,PyObject *Args) +{ + char *A; + char *B; + Py_ssize_t LenA; + Py_ssize_t LenB; + + if (PyArg_ParseTuple(Args,"s#s#",&A,&LenA,&B,&LenB) == 0) + return 0; + + if (_system == 0) + { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + + return MkPyNumber(_system->VS->DoCmpVersion(A,A+LenA,B,B+LenB)); +} + +static char *doc_CheckDep = + "check_dep(pkg_ver: str, dep_op: str, dep_ver: str) -> bool\n\n" + "Check that the given requirement is fulfilled; i.e. that the version\n" + "string given by 'pkg_ver' matches the version string 'dep_ver' under\n" + "the condition specified by the operator 'dep_op' (<,<=,=,>=,>).\n\n" + "Return True if 'pkg_ver' matches 'dep_ver' under the\n" + "condition 'dep_op'; for example, this returns True:\n\n" + " apt_pkg.check_dep('1', '<=', '2')"; +static PyObject *CheckDep(PyObject *Self,PyObject *Args) +{ + char *A; + char *B; + char *OpStr; + unsigned int Op = 0; + + if (PyArg_ParseTuple(Args,"sss",&A,&OpStr,&B) == 0) + return 0; + + if (strcmp(OpStr, ">") == 0) OpStr = ">>"; + if (strcmp(OpStr, "<") == 0) OpStr = "<<"; + if (*debListParser::ConvertRelation(OpStr,Op) != 0) + { + PyErr_SetString(PyExc_ValueError,"Bad comparison operation"); + return 0; + } + + if (_system == 0) + { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + + return PyBool_FromLong(_system->VS->CheckDep(A,Op,B)); +} + + +static char *doc_UpstreamVersion = + "upstream_version(ver: str) -> str\n\n" + "Return the upstream version for the package version given by 'ver'."; +static PyObject *UpstreamVersion(PyObject *Self,PyObject *Args) +{ + char *Ver; + if (PyArg_ParseTuple(Args,"s",&Ver) == 0) + return 0; + return CppPyString(_system->VS->UpstreamVersion(Ver)); +} + +static const char *doc_ParseDepends = +"parse_depends(s: str[, strip_multi_arch : bool = True[, architecture : string]]) -> list\n" +"\n" +"Parse the dependencies given by 's' and return a list of lists. Each of\n" +"these lists represents one or more options for an 'or' dependency in\n" +"the form of '(pkg, ver, comptype)' tuples. The tuple element 'pkg'\n" +"is the name of the package; the element 'ver' is the version, or ''\n" +"if no version was requested. The element 'ver' is a comparison\n" +"operator ('<', '<=', '=', '>=', or '>').\n\n" +"If 'strip_multi_arch' is True, :any (and potentially other special values)\n" +"will be stripped from the full package name" +"The 'architecture' parameter may be used to specify a non-native architecture\n" +"for the dependency parsing."; + +static const char *parse_src_depends_doc = +"parse_src_depends(s: str[, strip_multi_arch : bool = True[, architecture : string]]) -> list\n" +"\n" +"Parse the dependencies given by 's' and return a list of lists. Each of\n" +"these lists represents one or more options for an 'or' dependency in\n" +"the form of '(pkg, ver, comptype)' tuples. The tuple element 'pkg'\n" +"is the name of the package; the element 'ver' is the version, or ''\n" +"if no version was requested. The element 'ver' is a comparison\n" +"operator ('<', '<=', '=', '>=', or '>')." +"\n\n" +"Dependencies may be restricted to certain architectures and the result\n" +"only contains those dependencies for the architecture set in the\n" +"configuration variable APT::Architecture\n\n" +"If 'strip_multi_arch' is True, :any (and potentially other special values)\n" +"will be stripped from the full package name" +"The 'architecture' parameter may be used to specify a non-native architecture\n" +"for the dependency parsing."; +static PyObject *RealParseDepends(PyObject *Self,PyObject *Args,PyObject *Kwds, + bool ParseArchFlags, bool ParseRestrictionsList, + std::string name, bool debStyle=false) +{ + std::string Package; + std::string Version; + unsigned int Op; + bool StripMultiArch=true; + + const char *Start; + const char *Stop; + Py_ssize_t Len; + const char *Arch = NULL; + char *kwlist[] = {"s", "strip_multi_arch", "architecture", 0}; + + if (PyArg_ParseTupleAndKeywords(Args,Kwds,(char *)("s#|bs:" + name).c_str(), kwlist, + &Start, &Len, &StripMultiArch, &Arch) == 0) + return 0; + Stop = Start + Len; + PyObject *List = PyList_New(0); + PyObject *LastRow = 0; + while (1) + { + if (Start == Stop) + break; + if (Arch == NULL) + Start = debListParser::ParseDepends(Start,Stop,Package,Version,Op, + ParseArchFlags, StripMultiArch, + ParseRestrictionsList); + else + Start = debListParser::ParseDepends(Start,Stop,Package,Version,Op, + ParseArchFlags, StripMultiArch, + ParseRestrictionsList, Arch); + + if (Start == 0) + { + PyErr_SetString(PyExc_ValueError,"Problem Parsing Dependency"); + Py_DECREF(List); + return 0; + } + + if (LastRow == 0) + LastRow = PyList_New(0); + + if (Package.empty() == false) + { + PyObject *Obj; + PyList_Append(LastRow,Obj = Py_BuildValue("sss",Package.c_str(), + Version.c_str(), + debStyle ? pkgCache::CompTypeDeb(Op) : pkgCache::CompType(Op))); + Py_DECREF(Obj); + } + + // Group ORd deps into a single row.. + if ((Op & pkgCache::Dep::Or) != pkgCache::Dep::Or) + { + if (PyList_Size(LastRow) != 0) + PyList_Append(List,LastRow); + Py_DECREF(LastRow); + LastRow = 0; + } + } + return List; +} +static PyObject *ParseDepends(PyObject *Self,PyObject *Args, PyObject *Kwds) +{ + return RealParseDepends(Self, Args, Kwds, false, false, "parse_depends"); +} +static PyObject *ParseSrcDepends(PyObject *Self,PyObject *Args, PyObject *Kwds) +{ + return RealParseDepends(Self, Args, Kwds, true, true, "parse_src_depends"); +} + /*}}}*/ +// md5sum - Compute the md5sum of a file or string /*{{{*/ +// --------------------------------------------------------------------- +static const char *doc_md5sum = + "md5sum(object) -> str\n\n" + "Return the md5sum of the object. 'object' may either be a string, in\n" + "which case the md5sum of the string is returned, or a file() object\n" + "(or file descriptor), in which case the md5sum of its contents is\n" + "returned."; +static PyObject *md5sum(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "apt_pkg.md5sum is deprecated, use apt_pkg.Hashes", 1) == -1) + return NULL; + + // Digest of a string. + if (PyBytes_Check(Obj) != 0) + { + char *s; + Py_ssize_t len; + Hashes Sum(Hashes::MD5SUM); + PyBytes_AsStringAndSize(Obj, &s, &len); + Sum.Add((const unsigned char*)s, len); + return CppPyString(Sum.GetHashString(Hashes::MD5SUM).HashValue()); + } + + // Digest of a file + int Fd = PyObject_AsFileDescriptor(Obj); + if (Fd != -1) + { + Hashes Sum(Hashes::MD5SUM); + struct stat St; + if (fstat(Fd,&St) != 0 || + Sum.AddFD(Fd,St.st_size) == false) + { + PyErr_SetFromErrno(PyAptError); + return 0; + } + + return CppPyString(Sum.GetHashString(Hashes::MD5SUM).HashValue()); + } + + PyErr_SetString(PyExc_TypeError,"Only understand strings and files"); + return 0; +} + /*}}}*/ +// sha1sum - Compute the sha1sum of a file or string /*{{{*/ +// --------------------------------------------------------------------- +static const char *doc_sha1sum = + "sha1sum(object) -> str\n\n" + "Return the sha1sum of the object. 'object' may either be a string, in\n" + "which case the sha1sum of the string is returned, or a file() object\n" + "(or file descriptor), in which case the sha1sum of its contents is\n" + "returned."; +static PyObject *sha1sum(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "apt_pkg.sha1sum is deprecated, use apt_pkg.Hashes", 1) == -1) + return NULL; + + // Digest of a string. + if (PyBytes_Check(Obj) != 0) + { + char *s; + Py_ssize_t len; + Hashes Sum(Hashes::SHA1SUM); + PyBytes_AsStringAndSize(Obj, &s, &len); + Sum.Add((const unsigned char*)s, len); + return CppPyString(Sum.GetHashString(Hashes::SHA1SUM).HashValue()); + } + + // Digest of a file + int Fd = PyObject_AsFileDescriptor(Obj); + if (Fd != -1) + { + Hashes Sum(Hashes::SHA1SUM); + struct stat St; + if (fstat(Fd,&St) != 0 || + Sum.AddFD(Fd,St.st_size) == false) + { + PyErr_SetFromErrno(PyAptError); + return 0; + } + + return CppPyString(Sum.GetHashString(Hashes::SHA1SUM).HashValue()); + } + + PyErr_SetString(PyExc_TypeError,"Only understand strings and files"); + return 0; +} + /*}}}*/ +// sha256sum - Compute the sha256sum of a file or string /*{{{*/ +// --------------------------------------------------------------------- +static const char *doc_sha256sum = + "sha256sum(object) -> str\n\n" + "Return the sha256sum of the object. 'object' may either be a string, in\n" + "which case the sha256sum of the string is returned, or a file() object\n" + "(or file descriptor), in which case the sha256sum of its contents is\n" + "returned.";; +static PyObject *sha256sum(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "apt_pkg.sha256sum is deprecated, use apt_pkg.Hashes", 1) == -1) + return NULL; + + // Digest of a string. + if (PyBytes_Check(Obj) != 0) + { + char *s; + Py_ssize_t len; + Hashes Sum(Hashes::SHA256SUM); + PyBytes_AsStringAndSize(Obj, &s, &len); + Sum.Add((const unsigned char*)s, len); + return CppPyString(Sum.GetHashString(Hashes::SHA256SUM).HashValue()); + } + + // Digest of a file + int Fd = PyObject_AsFileDescriptor(Obj); + if (Fd != -1) + { + Hashes Sum(Hashes::SHA256SUM); + struct stat St; + if (fstat(Fd,&St) != 0 || + Sum.AddFD(Fd,St.st_size) == false) + { + PyErr_SetFromErrno(PyAptError); + return 0; + } + + return CppPyString(Sum.GetHashString(Hashes::SHA256SUM).HashValue()); + } + + PyErr_SetString(PyExc_TypeError,"Only understand strings and files"); + return 0; +} + /*}}}*/ +// sha512sum - Compute the sha512sum of a file or string /*{{{*/ +// --------------------------------------------------------------------- +static const char *doc_sha512sum = + "sha512sum(object) -> str\n\n" + "Return the sha512sum of the object. 'object' may either be a string, in\n" + "which case the sha512sum of the string is returned, or a file() object\n" + "(or file descriptor), in which case the sha512sum of its contents is\n" + "returned.";; +static PyObject *sha512sum(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "apt_pkg.sha512sum is deprecated, use apt_pkg.Hashes", 1) == -1) + return NULL; + + // Digest of a string. + if (PyBytes_Check(Obj) != 0) + { + char *s; + Py_ssize_t len; + Hashes Sum(Hashes::SHA512SUM); + PyBytes_AsStringAndSize(Obj, &s, &len); + Sum.Add((const unsigned char*)s, len); + return CppPyString(Sum.GetHashString(Hashes::SHA512SUM).HashValue()); + } + + // Digest of a file + int Fd = PyObject_AsFileDescriptor(Obj); + if (Fd != -1) + { + Hashes Sum(Hashes::SHA512SUM); + struct stat St; + if (fstat(Fd,&St) != 0 || + Sum.AddFD(Fd,St.st_size) == false) + { + PyErr_SetFromErrno(PyAptError); + return 0; + } + + return CppPyString(Sum.GetHashString(Hashes::SHA512SUM).HashValue()); + } + + PyErr_SetString(PyExc_TypeError,"Only understand strings and files"); + return 0; +} + /*}}}*/ +// get_architectures - return the list of architectures /*{{{*/ +// --------------------------------------------------------------------- +static const char *doc_GetArchitectures = + "get_architectures() -> list\n\n" + "Return the list of supported architectures on this system. On a \n" + "multiarch system this can be more than one. The main architectures\n" + "is the first item in the list.";; +static PyObject *GetArchitectures(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"",&Obj) == 0) + return 0; + + PyObject *List = PyList_New(0); + std::vector<std::string> arches = APT::Configuration::getArchitectures(); + std::vector<std::string>::const_iterator I; + for (I = arches.begin(); I != arches.end(); I++) + { + PyList_Append(List, CppPyString(*I)); + } + + return List; +} + /*}}}*/ +// init - 3 init functions /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_Init = +"init()\n\n" +"Shorthand for doing init_config() and init_system(). When working\n" +"with command line arguments, first call init_config() then parse\n" +"the command line and finally call init_system()."; +static PyObject *Init(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitConfig(*_config); + pkgInitSystem(*_config,_system); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static char *doc_InitConfig = +"init_config()\n\n" +"Load the default configuration and the config file."; +static PyObject *InitConfig(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitConfig(*_config); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static char *doc_InitSystem = +"init_system()\n\n" +"Construct the apt_pkg system."; +static PyObject *InitSystem(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitSystem(*_config,_system); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + /*}}}*/ +// gpgv.cc:OpenMaybeClearSignedFile /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_OpenMaybeClearSignedFile = +"open_maybe_clear_signed_file(file: str) -> int\n\n" +"Open a file and ignore a PGP clear signature.\n" +"Return a open file descriptor or a error."; +static PyObject *PyOpenMaybeClearSignedFile(PyObject *Self,PyObject *Args) +{ + PyApt_Filename file; + char errors = false; + if (PyArg_ParseTuple(Args,"O&",PyApt_Filename::Converter, &file,&errors) == 0) + return 0; + + FileFd Fd; + if (OpenMaybeClearSignedFile(file, Fd) == false) + return HandleErrors(MkPyNumber(-1)); + + return HandleErrors(MkPyNumber(dup(Fd.Fd()))); +} + +// fileutils.cc: GetLock /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_GetLock = +"get_lock(file: str, errors: bool) -> int\n\n" +"Create an empty file of the given name and lock it. If the locking\n" +"succeeds, return the file descriptor of the lock file. Afterwards,\n" +"locking the file from another process will fail and thus cause\n" +"get_lock() to return -1 or raise an Error (if 'errors' is True).\n\n" +"From Python 2.6 on, it is recommended to use the context manager\n" +"provided by apt_pkg.FileLock instead using the with-statement."; +static PyObject *GetLock(PyObject *Self,PyObject *Args) +{ + PyApt_Filename file; + char errors = false; + if (PyArg_ParseTuple(Args,"O&|b",PyApt_Filename::Converter, &file,&errors) == 0) + return 0; + + int fd = GetLock(file, errors); + + return HandleErrors(MkPyNumber(fd)); +} + +static char *doc_PkgSystemLock = +"pkgsystem_lock() -> bool\n\n" +"Acquire the global lock for the package system by using /var/lib/dpkg/lock-frontend\n" +"and /var/lib/dpkg/lock to do the locking. From Python 2.6 on, the apt_pkg.SystemLock context\n" +"manager is available and should be used instead."; +static PyObject *PkgSystemLock(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = _system->Lock(); + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + +static char *doc_PkgSystemUnLock = +"pkgsystem_unlock() -> bool\n\n" +"Release the global lock for the package system."; +static PyObject *PkgSystemUnLock(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = _system->UnLock(); + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + +static char *doc_PkgSystemLockInner = +"pkgsystem_lock_inner() -> bool\n\n" +"Reacquire the dpkg 'lock' lock file. Must be called only after\n" +":meth:`pkgsystem_unlock_inner` and only around invocations of dpkg.\n" +"\n" +".. versionadded:: 1.7"; +static PyObject *PkgSystemLockInner(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = _system->LockInner(); + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + +static char *doc_PkgSystemUnLockInner = +"pkgsystem_unlock_inner() -> bool\n\n" +"Release the dpkg lock file 'lock'. To be called before manually\n" +"invoking dpkg.\n" +"\n" +".. versionadded:: 1.7"; +static PyObject *PkgSystemUnLockInner(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = _system->UnLockInner(); + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + +static char *doc_PkgSystemIsLocked = +"pkgsystem_is_locked() -> bool\n\n" +"Check if the system is locked. Can be used to check whether the inner\n" +"lock needs to be released or not in generic code.\n" +"\n" +".. versionadded:: 1.7"; +static PyObject *PkgSystemIsLocked(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = _system->IsLocked(); + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + + /*}}}*/ + +// initapt_pkg - Core Module Initialization /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyMethodDef methods[] = +{ + // Constructors + {"init",Init,METH_VARARGS,doc_Init}, + {"init_config",InitConfig,METH_VARARGS,doc_InitConfig}, + {"init_system",InitSystem,METH_VARARGS,doc_InitSystem}, + + // Internationalization. + {"gettext",py_gettext,METH_VARARGS, + "gettext(msg: str[, domain: str = 'python-apt']) -> str\n\n" + "Translate the given string. This is much faster than Python's version\n" + "and only does translations after setlocale() has been called."}, + + // Tag File + + {"open_maybe_clear_signed_file",PyOpenMaybeClearSignedFile,METH_VARARGS, + doc_OpenMaybeClearSignedFile}, + + // Locking + {"get_lock",GetLock,METH_VARARGS,doc_GetLock}, + {"pkgsystem_lock",PkgSystemLock,METH_VARARGS,doc_PkgSystemLock}, + {"pkgsystem_unlock",PkgSystemUnLock,METH_VARARGS,doc_PkgSystemUnLock}, + {"pkgsystem_lock_inner",PkgSystemLockInner,METH_VARARGS,doc_PkgSystemLockInner}, + {"pkgsystem_unlock_inner",PkgSystemUnLockInner,METH_VARARGS,doc_PkgSystemUnLockInner}, + {"pkgsystem_is_locked",PkgSystemIsLocked,METH_VARARGS,doc_PkgSystemIsLocked}, + + // Command line + {"read_config_file",LoadConfig,METH_VARARGS,doc_LoadConfig}, + {"read_config_dir",LoadConfigDir,METH_VARARGS,doc_LoadConfigDir}, + {"read_config_file_isc",LoadConfigISC,METH_VARARGS,doc_LoadConfig}, + {"parse_commandline",ParseCommandLine,METH_VARARGS,doc_ParseCommandLine}, + + // Versioning + {"version_compare",VersionCompare,METH_VARARGS,doc_VersionCompare}, + {"check_dep",CheckDep,METH_VARARGS,doc_CheckDep}, + {"upstream_version",UpstreamVersion,METH_VARARGS,doc_UpstreamVersion}, + + // Depends + {"parse_depends",reinterpret_cast<PyCFunction>(static_cast<PyCFunctionWithKeywords>(ParseDepends)),METH_VARARGS|METH_KEYWORDS,doc_ParseDepends}, + {"parse_src_depends",reinterpret_cast<PyCFunction>(static_cast<PyCFunctionWithKeywords>(ParseSrcDepends)),METH_VARARGS|METH_KEYWORDS,parse_src_depends_doc}, + + // Hashes + {"md5sum",md5sum,METH_VARARGS,doc_md5sum}, + {"sha1sum",sha1sum,METH_VARARGS,doc_sha1sum}, + {"sha256sum",sha256sum,METH_VARARGS,doc_sha256sum}, + {"sha512sum",sha512sum,METH_VARARGS,doc_sha512sum}, + + // multiarch + {"get_architectures", GetArchitectures, METH_VARARGS, doc_GetArchitectures}, + + // Strings + {"check_domain_list",StrCheckDomainList,METH_VARARGS, + "check_domain_list(host: str, domains: str) -> bool\n\n" + "Check if the host given by 'host' belongs to one of the domains\n" + "specified in the comma separated string 'domains'. An example\n" + "would be:\n\n" + " check_domain_list('alioth.debian.org','debian.net,debian.org')\n\n" + "which would return True because alioth belongs to debian.org."}, + {"quote_string",StrQuoteString,METH_VARARGS, + "quote_string(string: str, repl: str) -> str\n\n" + "Escape the string 'string', replacing any character not allowed in a URL" + "or specified by 'repl' with its ASCII value preceded by a percent sign" + "(so for example ' ' becomes '%20')."}, + {"dequote_string",StrDeQuote,METH_VARARGS, + "dequote_string(string: str) -> str\n\n" + "Dequote the given string by replacing all HTTP encoded values such\n" + "as '%20' with their decoded value (in this case, ' ')."}, + {"size_to_str",StrSizeToStr,METH_VARARGS, + "size_to_str(bytes: int) -> str\n\n" + "Return a string describing the size in a human-readable manner using\n" + "SI prefix and base-10 units, e.g. '1k' for 1000, '1M' for 1000000, etc."}, + {"time_to_str",StrTimeToStr,METH_VARARGS, + "time_to_str(seconds: int) -> str\n\n" + "Return a string describing the number of seconds in a human\n" + "readable manner using days, hours, minutes and seconds."}, + {"uri_to_filename",StrURItoFileName,METH_VARARGS, + "uri_to_filename(uri: str) -> str\n\n" + "Return a filename based on the given URI after replacing some\n" + "parts not suited for filenames (e.g. '/')."}, + {"base64_encode",StrBase64Encode,METH_VARARGS, + "base64_encode(value: bytes) -> str\n\n" + "Encode the given bytestring into Base64. The input may not\n" + "contain a null byte character (use the base64 module for this)."}, + {"string_to_bool",StrStringToBool,METH_VARARGS, + "string_to_bool(string: str) -> int\n\n" + "Return 1 if the string is a value such as 'yes', 'true', '1';\n" + "0 if the string is a value such as 'no', 'false', '0'; -1 if\n" + "the string is not recognized."}, + {"time_rfc1123",StrTimeRFC1123,METH_VARARGS, + "time_rfc1123(unixtime: int) -> str\n\n" + "Format the given Unix time according to the requirements of\n" + "RFC 1123."}, + {"str_to_time",StrStrToTime,METH_VARARGS, + "str_to_time(rfc_time: str) -> int\n\n" + "Convert the given RFC 1123 formatted string to a Unix timestamp."}, + + // DEPRECATED + + {} +}; + +static struct _PyAptPkgAPIStruct API = { + &PyAcquire_Type, // acquire_type + &PyAcquire_FromCpp, // acquire_fromcpp + &PyAcquire_ToCpp, // acquire_tocpp + &PyAcquireFile_Type, // acquirefile_type + &PyAcquireFile_FromCpp, // acquirefile_fromcpp + &PyAcquireFile_ToCpp, // acquirefile_tocpp + &PyAcquireItem_Type, // acquireitem_type + &PyAcquireItem_FromCpp, // acquireitem_fromcpp + &PyAcquireItem_ToCpp, // acquireitem_type + &PyAcquireItemDesc_Type, // acquireitemdesc_type + &PyAcquireItemDesc_FromCpp,// acquireitemdesc_fromcpp + &PyAcquireItemDesc_ToCpp, // acquireitemdesc_tocpp + &PyAcquireWorker_Type, // acquireworker_type + &PyAcquireWorker_FromCpp, // acquireworker_fromcpp + &PyAcquireWorker_ToCpp, // acquireworker_tocpp + &PyActionGroup_Type, // actiongroup_type + &PyActionGroup_FromCpp, // actiongroup_fromcpp + &PyActionGroup_ToCpp, // actiongroup_tocpp + &PyCache_Type, // cache_type + &PyCache_FromCpp, // cache_fromcpp + &PyCache_ToCpp, // cache_tocpp + &PyCacheFile_Type, // cachefile_type + &PyCacheFile_FromCpp, // cachefile_fromcpp + &PyCacheFile_ToCpp, // cachefile_tocpp + &PyCdrom_Type, // cdrom_type + &PyCdrom_FromCpp, // cdrom_fromcpp + &PyCdrom_ToCpp, // cdrom_tocpp + &PyConfiguration_Type, // configuration_type + &PyConfiguration_FromCpp, // configuration_fromcpp + &PyConfiguration_ToCpp, // configuration_tocpp + &PyDepCache_Type, // depcache_type + &PyDepCache_FromCpp, // depcache_fromcpp + &PyDepCache_ToCpp, // depcache_tocpp + &PyDependency_Type, // dependency_type + &PyDependency_FromCpp, // dependency_fromcpp + &PyDependency_ToCpp, // dependency_tocpp + &PyDependencyList_Type, // dependencylist_type + 0, // FIXME: dependencylist_fromcpp + 0, // FIXME: dependencylist_tocpp + &PyDescription_Type, // description_type + &PyDescription_FromCpp, // description_fromcpp + &PyDescription_ToCpp, // description_tocpp + &PyHashes_Type, // hashes_type + &PyHashes_FromCpp, // hashes_fromcpp + &PyHashes_ToCpp, // hashes_tocpp + &PyHashString_Type, // hashstring_type + &PyHashString_FromCpp, // hashstring_fromcpp + &PyHashString_ToCpp, // hashstring_tocpp + &PyMetaIndex_Type, // metaindex_type + &PyMetaIndex_FromCpp, // metaindex_tocpp + &PyMetaIndex_ToCpp, // metaindex_tocpp + &PyPackage_Type, // package_type + &PyPackage_FromCpp, // package_tocpp + &PyPackage_ToCpp, // package_tocpp + &PyPackageFile_Type, // packagefile_type + &PyPackageFile_FromCpp, // packagefile_tocpp + &PyPackageFile_ToCpp, // packagefile_tocpp + &PyIndexFile_Type, // packageindexfile_type + &PyIndexFile_FromCpp, // packageindexfile_tocpp + &PyIndexFile_ToCpp, // packageindexfile_tocpp + &PyPackageList_Type, // packagelist_type + 0, // FIXME: packagelist_fromcpp + 0, // FIXME: packagelist_tocpp + &PyPackageManager_Type, // packagemanager_type + &PyPackageManager_FromCpp, // packagemanager_type + &PyPackageManager_ToCpp, // packagemanager_type + &PyPackageRecords_Type, // packagerecords_type + 0, // FIXME: packagerecords_fromcpp + 0, // FIXME: packagerecords_tocpp + &PyPolicy_Type, // policy_type + &PyPolicy_FromCpp, // policy_tocpp + &PyPolicy_ToCpp, // policy_tocpp + &PyProblemResolver_Type, // problemresolver_type + &PyProblemResolver_FromCpp, // problemresolver_tocpp + &PyProblemResolver_ToCpp, // problemresolver_tocpp + &PySourceList_Type, // sourcelist_type + &PySourceList_FromCpp, // sourcelist_tocpp + &PySourceList_ToCpp, // sourcelist_tocpp + &PySourceRecords_Type, // sourcerecords_type + 0, // FIXME: sourcerecords_fromcpp + 0, // FIXME: sourcerecords_tocpp + &PyTagFile_Type, // tagfile_type + &PyTagFile_FromCpp, // tagfile_tocpp + &PyTagFile_ToCpp, // tagfile_tocpp + &PyTagSection_Type, // tagsection_type + &PyTagSection_FromCpp, // tagsection_tocpp + &PyTagSection_ToCpp, // tagsection_tocpp + &PyVersion_Type, // version_type + &PyVersion_FromCpp, // version_tocpp + &PyVersion_ToCpp, // version_tocpp + &PyGroup_Type, // group_type + &PyGroup_FromCpp, // group_fromcpp + &PyGroup_ToCpp, // group_tocpp + &PyOrderList_Type, // orderlist_type + &PyOrderList_FromCpp, // orderlist_fromcpp + &PyOrderList_ToCpp, // orderlist_tocpp + &PySourceRecordFiles_Type, // sourcerecordfiles_type + 0, // FIXME: sourcerecordfiles_fromcpp + 0, // FIXME: sourcerecordfiles_tocpp +}; + + +#define ADDTYPE(mod,name,type) { \ + if (PyType_Ready(type) == -1) INIT_ERROR; \ + Py_INCREF(type); \ + PyModule_AddObject(mod,name,(PyObject *)type); } + + +static const char *apt_pkg_doc = + "Classes and functions wrapping the apt-pkg library.\n\n" + "The apt_pkg module provides several classes and functions for accessing\n" + "the functionality provided by the apt-pkg library. Typical uses might\n" + "include reading APT index files and configuration files and installing\n" + "or removing packages."; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "apt_pkg", + apt_pkg_doc, + -1, + methods, + 0, + 0, + 0, + 0, +}; + +#define INIT_ERROR return 0 +extern "C" PyObject * PyInit_apt_pkg() +#else +#define INIT_ERROR return +extern "C" void initapt_pkg() +#endif +{ + // Finalize our types to add slots, etc. + if (PyType_Ready(&PyConfiguration_Type) == -1) INIT_ERROR; + if (PyType_Ready(&PyCacheFile_Type) == -1) INIT_ERROR; + PyAptError = PyErr_NewExceptionWithDoc("apt_pkg.Error", PyAptError_Doc, PyExc_SystemError, NULL); + if (PyAptError == NULL) + INIT_ERROR; + PyAptWarning = PyErr_NewExceptionWithDoc("apt_pkg.Warning", PyAptWarning_Doc, PyExc_Warning, NULL); + if (PyAptWarning == NULL) + INIT_ERROR; + + PyAptCacheMismatchError = PyErr_NewExceptionWithDoc("apt_pkg.CacheMismatchError", PyAptCacheMismatchError_Doc, PyExc_ValueError, NULL); + if (PyAptCacheMismatchError == NULL) + INIT_ERROR; + + // Initialize the module + #if PY_MAJOR_VERSION >= 3 + PyObject *Module = PyModule_Create(&moduledef); + #else + PyObject *Module = Py_InitModule3("apt_pkg",methods, apt_pkg_doc); + #endif + + // Global variable linked to the global configuration class + CppPyObject<Configuration*> *Config = CppPyObject_NEW<Configuration*>(NULL, &PyConfiguration_Type); + Config->Object = _config; + // Global configuration, should never be deleted. + Config->NoDelete = true; + PyModule_AddObject(Module,"config",Config); + PyModule_AddObject(Module,"Error",PyAptError); + PyModule_AddObject(Module,"Warning",PyAptWarning); + PyModule_AddObject(Module,"CacheMismatchError", PyAptCacheMismatchError); + + + + // Add our classes. + /* ============================ tag.cc ============================ */ + ADDTYPE(Module,"TagSection",&PyTagSection_Type); + ADDTYPE(Module,"TagFile",&PyTagFile_Type); + ADDTYPE(Module,"Tag",&PyTag_Type); + ADDTYPE(Module,"TagRewrite",&PyTagRewrite_Type); + ADDTYPE(Module,"TagRename",&PyTagRename_Type); + ADDTYPE(Module,"TagRemove",&PyTagRemove_Type); + /* ============================ acquire.cc ============================ */ + ADDTYPE(Module,"Acquire",&PyAcquire_Type); + ADDTYPE(Module,"AcquireFile",&PyAcquireFile_Type); + ADDTYPE(Module,"AcquireItem",&PyAcquireItem_Type); // NO __new__() + ADDTYPE(Module,"AcquireWorker",&PyAcquireWorker_Type); // NO __new__() + /* ============================ cache.cc ============================ */ + ADDTYPE(Module,"Cache",&PyCache_Type); + ADDTYPE(Module,"Dependency",&PyDependency_Type); // NO __new__() + ADDTYPE(Module,"Description",&PyDescription_Type); // NO __new__() + ADDTYPE(Module,"PackageFile",&PyPackageFile_Type); // NO __new__() + ADDTYPE(Module,"PackageList",&PyPackageList_Type); // NO __new__(), internal + ADDTYPE(Module,"DependencyList",&PyDependencyList_Type); // NO __new__(), internal + ADDTYPE(Module,"Package",&PyPackage_Type); // NO __new__() + ADDTYPE(Module,"Version",&PyVersion_Type); // NO __new__() + ADDTYPE(Module,"Group", &PyGroup_Type); + ADDTYPE(Module,"GroupList", &PyGroupList_Type); + /* ============================ cdrom.cc ============================ */ + ADDTYPE(Module,"Cdrom",&PyCdrom_Type); + /* ========================= configuration.cc ========================= */ + ADDTYPE(Module,"Configuration",&PyConfiguration_Type); + /* ========================= depcache.cc ========================= */ + ADDTYPE(Module,"ActionGroup",&PyActionGroup_Type); + ADDTYPE(Module,"DepCache",&PyDepCache_Type); + ADDTYPE(Module,"ProblemResolver",&PyProblemResolver_Type); + /* ========================= indexfile.cc ========================= */ + ADDTYPE(Module,"IndexFile",&PyIndexFile_Type); // NO __new__() + /* ========================= metaindex.cc ========================= */ + ADDTYPE(Module,"MetaIndex",&PyMetaIndex_Type); // NO __new__() + /* ========================= pkgmanager.cc ========================= */ + ADDTYPE(Module,"_PackageManager",&PyPackageManager_Type); + ADDTYPE(Module,"PackageManager",&PyPackageManager2_Type); + /* ========================= pkgrecords.cc ========================= */ + ADDTYPE(Module,"PackageRecords",&PyPackageRecords_Type); + /* ========================= pkgsrcrecords.cc ========================= */ + ADDTYPE(Module,"SourceRecords",&PySourceRecords_Type); + ADDTYPE(Module,"SourceRecordFiles",&PySourceRecordFiles_Type); + /* ========================= sourcelist.cc ========================= */ + ADDTYPE(Module,"SourceList",&PySourceList_Type); + ADDTYPE(Module,"HashString",&PyHashString_Type); + ADDTYPE(Module,"Policy",&PyPolicy_Type); + ADDTYPE(Module,"Hashes",&PyHashes_Type); + ADDTYPE(Module,"AcquireItemDesc",&PyAcquireItemDesc_Type); + ADDTYPE(Module,"SystemLock",&PySystemLock_Type); + ADDTYPE(Module,"FileLock",&PyFileLock_Type); + ADDTYPE(Module,"OrderList",&PyOrderList_Type); + ADDTYPE(Module,"HashStringList",&PyHashStringList_Type); + // Tag file constants + PyModule_AddObject(Module,"REWRITE_PACKAGE_ORDER", + CharCharToList(TFRewritePackageOrder)); + + PyModule_AddObject(Module,"REWRITE_SOURCE_ORDER", + CharCharToList(TFRewriteSourceOrder)); + + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_ADDED", MkPyNumber(pkgOrderList::Added)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_ADD_PENDIG", MkPyNumber(pkgOrderList::AddPending)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_IMMEDIATE", MkPyNumber(pkgOrderList::Immediate)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_LOOP", MkPyNumber(pkgOrderList::Loop)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_UNPACKED", MkPyNumber(pkgOrderList::UnPacked)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_CONFIGURED", MkPyNumber(pkgOrderList::Configured)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_REMOVED", MkPyNumber(pkgOrderList::Removed)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_IN_LIST", MkPyNumber(pkgOrderList::InList)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_AFTER", MkPyNumber(pkgOrderList::After)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_STATES_MASK", MkPyNumber(pkgOrderList::States)); + + // Acquire constants. + // some constants + PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_CANCELLED", + MkPyNumber(pkgAcquire::Cancelled)); + PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_CONTINUE", + MkPyNumber(pkgAcquire::Continue)); + PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_FAILED", + MkPyNumber(pkgAcquire::Failed)); + // Dependency constants + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_DEPENDS", + MkPyNumber(pkgCache::Dep::Depends)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_PREDEPENDS", + MkPyNumber(pkgCache::Dep::PreDepends)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_SUGGESTS", + MkPyNumber(pkgCache::Dep::Suggests)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_RECOMMENDS", + MkPyNumber(pkgCache::Dep::Recommends)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_CONFLICTS", + MkPyNumber(pkgCache::Dep::Conflicts)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_REPLACES", + MkPyNumber(pkgCache::Dep::Replaces)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_OBSOLETES", + MkPyNumber(pkgCache::Dep::Obsoletes)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_DPKG_BREAKS", + MkPyNumber(pkgCache::Dep::DpkgBreaks)); + PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_ENHANCES", + MkPyNumber(pkgCache::Dep::Enhances)); + + + // PackageManager constants + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_COMPLETED", + MkPyNumber(pkgPackageManager::Completed)); + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_FAILED", + MkPyNumber(pkgPackageManager::Failed)); + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_INCOMPLETE", + MkPyNumber(pkgPackageManager::Incomplete)); + + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_NO", + MkPyNumber(pkgCache::Version::No)); + // NONE is deprecated (#782802) + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_NONE", + MkPyNumber(pkgCache::Version::No)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL", + MkPyNumber(pkgCache::Version::All)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_FOREIGN", + MkPyNumber(pkgCache::Version::Foreign)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_SAME", + MkPyNumber(pkgCache::Version::Same)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALLOWED", + MkPyNumber(pkgCache::Version::Allowed)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL_FOREIGN", + MkPyNumber(pkgCache::Version::AllForeign)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL_ALLOWED", + MkPyNumber(pkgCache::Version::AllAllowed)); + // AcquireItem Constants. + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_IDLE", + MkPyNumber(pkgAcquire::Item::StatIdle)); + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_FETCHING", + MkPyNumber(pkgAcquire::Item::StatFetching)); + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_DONE", + MkPyNumber(pkgAcquire::Item::StatDone)); + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_TRANSIENT_NETWORK_ERROR", + MkPyNumber(pkgAcquire::Item::StatTransientNetworkError)); + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_ERROR", + MkPyNumber(pkgAcquire::Item::StatError)); + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_AUTH_ERROR", + MkPyNumber(pkgAcquire::Item::StatAuthError)); + // TagSection constants + PyDict_SetItemString(PyTag_Type.tp_dict, "REMOVE", + MkPyNumber(pkgTagSection::Tag::REMOVE)); + PyDict_SetItemString(PyTag_Type.tp_dict, "REWRITE", + MkPyNumber(pkgTagSection::Tag::REWRITE)); + PyDict_SetItemString(PyTag_Type.tp_dict, "RENAME", + MkPyNumber(pkgTagSection::Tag::RENAME)); + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1 + PyObject *PyCapsule = PyCapsule_New(&API, "apt_pkg._C_API", NULL); +#else + PyObject *PyCapsule = PyCObject_FromVoidPtr(&API, NULL); +#endif + PyModule_AddObject(Module, "_C_API", PyCapsule); + // Version.. + PyModule_AddStringConstant(Module,"VERSION",(char *)pkgVersion); + PyModule_AddStringConstant(Module,"LIB_VERSION",(char *)pkgLibVersion); +#ifdef DATE + PyModule_AddStringConstant(Module,"DATE",DATE); + PyModule_AddStringConstant(Module,"TIME",TIME); +#else + PyModule_AddStringConstant(Module,"DATE", "Jan 1 1970"); + PyModule_AddStringConstant(Module,"TIME", "00:00:00"); +#endif + + // My constants + PyModule_AddIntConstant(Module,"PRI_IMPORTANT",pkgCache::State::Important); + PyModule_AddIntConstant(Module,"PRI_REQUIRED",pkgCache::State::Required); + PyModule_AddIntConstant(Module,"PRI_STANDARD",pkgCache::State::Standard); + PyModule_AddIntConstant(Module,"PRI_OPTIONAL",pkgCache::State::Optional); + PyModule_AddIntConstant(Module,"PRI_EXTRA",pkgCache::State::Extra); + // CurState + PyModule_AddIntConstant(Module,"CURSTATE_NOT_INSTALLED",pkgCache::State::NotInstalled); + PyModule_AddIntConstant(Module,"CURSTATE_UNPACKED",pkgCache::State::UnPacked); + PyModule_AddIntConstant(Module,"CURSTATE_HALF_CONFIGURED",pkgCache::State::HalfConfigured); + PyModule_AddIntConstant(Module,"CURSTATE_HALF_INSTALLED",pkgCache::State::HalfInstalled); + PyModule_AddIntConstant(Module,"CURSTATE_CONFIG_FILES",pkgCache::State::ConfigFiles); + PyModule_AddIntConstant(Module,"CURSTATE_INSTALLED",pkgCache::State::Installed); + // SelState + PyModule_AddIntConstant(Module,"SELSTATE_UNKNOWN",pkgCache::State::Unknown); + PyModule_AddIntConstant(Module,"SELSTATE_INSTALL",pkgCache::State::Install); + PyModule_AddIntConstant(Module,"SELSTATE_HOLD",pkgCache::State::Hold); + PyModule_AddIntConstant(Module,"SELSTATE_DEINSTALL",pkgCache::State::DeInstall); + PyModule_AddIntConstant(Module,"SELSTATE_PURGE",pkgCache::State::Purge); + // InstState + PyModule_AddIntConstant(Module,"INSTSTATE_OK",pkgCache::State::Ok); + PyModule_AddIntConstant(Module,"INSTSTATE_REINSTREQ",pkgCache::State::ReInstReq); + PyModule_AddIntConstant(Module,"INSTSTATE_HOLD",pkgCache::State::Hold); + PyModule_AddIntConstant(Module,"INSTSTATE_HOLD_REINSTREQ",pkgCache::State::HoldReInstReq); + + #if PY_MAJOR_VERSION >= 3 + return Module; + #endif +} + /*}}}*/ + diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h new file mode 100644 index 0000000..ee92c50 --- /dev/null +++ b/python/apt_pkgmodule.h @@ -0,0 +1,214 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_pkgmodule.h,v 1.4 2003/07/23 02:20:24 mdz Exp $ +/* ###################################################################### + + Prototypes for the module + + ##################################################################### */ + /*}}}*/ +#ifndef APT_PKGMODULE_H +#define APT_PKGMODULE_H + +#include <Python.h> +#include <apt-pkg/hashes.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/version.h> +#include <apt-pkg/deblistparser.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/init.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/cdrom.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/metaindex.h> +#include "generic.h" + +// Configuration Stuff +extern PyTypeObject PyConfiguration_Type; +extern PyTypeObject PyVersion_Type; + +extern char *doc_LoadConfig; +extern char *doc_LoadConfigISC; +extern char *doc_LoadConfigDir; +extern char *doc_ParseCommandLine; +PyObject *LoadConfig(PyObject *Self,PyObject *Args); +PyObject *LoadConfigISC(PyObject *Self,PyObject *Args); +PyObject *LoadConfigDir(PyObject *Self,PyObject *Args); +PyObject *ParseCommandLine(PyObject *Self,PyObject *Args); + +// Tag File Stuff +extern PyTypeObject PyTagSection_Type; +extern PyTypeObject PyTagFile_Type; +extern PyTypeObject PyTag_Type; +extern PyTypeObject PyTagRewrite_Type; +extern PyTypeObject PyTagRename_Type; +extern PyTypeObject PyTagRemove_Type; +extern char *doc_ParseSection; +extern char *doc_ParseTagFile; +PyObject *ParseSection(PyObject *self,PyObject *Args); +PyObject *ParseTagFile(PyObject *self,PyObject *Args); + +// String Stuff +PyObject *StrQuoteString(PyObject *self,PyObject *Args); +PyObject *StrDeQuote(PyObject *self,PyObject *Args); +PyObject *StrSizeToStr(PyObject *self,PyObject *Args); +PyObject *StrTimeToStr(PyObject *self,PyObject *Args); +PyObject *StrURItoFileName(PyObject *self,PyObject *Args); +PyObject *StrBase64Encode(PyObject *self,PyObject *Args); +PyObject *StrStringToBool(PyObject *self,PyObject *Args); +PyObject *StrTimeRFC1123(PyObject *self,PyObject *Args); +PyObject *StrStrToTime(PyObject *self,PyObject *Args); +PyObject *StrCheckDomainList(PyObject *Self,PyObject *Args); + +PyObject *PyAcquire_GetItem(PyObject *self, pkgAcquire::Item *item); +PyObject *PyAcquire_GetItemDesc(PyObject *self, pkgAcquire::ItemDesc *item); +bool PyAcquire_DropItem(PyObject *self, pkgAcquire::Item *item); + +// Cache Stuff +extern PyTypeObject PyCache_Type; +extern PyTypeObject PyCacheFile_Type; +extern PyTypeObject PyPackageList_Type; +extern PyTypeObject PyDescription_Type; +extern PyTypeObject PyGroup_Type; +extern PyTypeObject PyGroupList_Type; /* internal */ +extern PyTypeObject PyPackage_Type; +extern PyTypeObject PyPackageFile_Type; +extern PyTypeObject PyDependency_Type; +extern PyTypeObject PyDependencyList_Type; +PyObject *TmpGetCache(PyObject *Self,PyObject *Args); + +// DepCache +extern PyTypeObject PyDepCache_Type; +PyObject *GetDepCache(PyObject *Self,PyObject *Args); + +// pkgProblemResolver +extern PyTypeObject PyProblemResolver_Type; +PyObject *GetPkgProblemResolver(PyObject *Self, PyObject *Args); +PyObject *GetPkgActionGroup(PyObject *Self, PyObject *Args); + +extern PyTypeObject PyActionGroup_Type; +// cdrom +extern PyTypeObject PyCdrom_Type; +PyObject *GetCdrom(PyObject *Self,PyObject *Args); + +// acquire +extern PyTypeObject PyAcquireItem_Type; +extern PyTypeObject PyAcquire_Type; +extern PyTypeObject PyAcquireFile_Type; +extern char *doc_GetPkgAcqFile; +PyObject *GetAcquire(PyObject *Self,PyObject *Args); +PyObject *GetPkgAcqFile(PyObject *Self, PyObject *Args, PyObject *kwds); + +// packagemanager +extern PyTypeObject PyPackageManager_Type; +extern PyTypeObject PyPackageManager2_Type; +PyObject *GetPkgManager(PyObject *Self,PyObject *Args); + + +// PkgRecords Stuff +extern PyTypeObject PyPackageRecords_Type; +extern PyTypeObject PySourceRecords_Type; +extern PyTypeObject PySourceRecordFiles_Type; +PyObject *GetPkgRecords(PyObject *Self,PyObject *Args); +PyObject *GetPkgSrcRecords(PyObject *Self,PyObject *Args); + +// pkgSourceList +extern PyTypeObject PySourceList_Type; +PyObject *GetPkgSourceList(PyObject *Self,PyObject *Args); + +// pkgSourceList +extern PyTypeObject PyIndexFile_Type; + +// metaIndex +extern PyTypeObject PyMetaIndex_Type; + +// HashString +extern PyTypeObject PyHashString_Type; + +extern PyTypeObject PyHashStringList_Type; + + +// Policy +extern PyTypeObject PyPolicy_Type; +extern PyTypeObject PyHashes_Type; +extern PyTypeObject PyAcquireItemDesc_Type; +extern PyTypeObject PyAcquireWorker_Type; +extern PyTypeObject PySystemLock_Type; +extern PyTypeObject PyFileLock_Type; +extern PyTypeObject PyOrderList_Type; + +// Functions to be exported in the public API. + +# define PyAcquire_ToCpp GetCpp<pkgAcquire*> +# define PyAcquireFile_ToCpp GetCpp<pkgAcqFile*> +# define PyAcquireItem_ToCpp GetCpp<pkgAcquire::Item*> +# define PyAcquireItemDesc_ToCpp GetCpp<pkgAcquire::ItemDesc*> +# define PyAcquireWorker_ToCpp GetCpp<pkgAcquire::Worker*> +# define PyActionGroup_ToCpp GetCpp<pkgDepCache::ActionGroup*> +# define PyCache_ToCpp GetCpp<pkgCache*> +# define PyCacheFile_ToCpp GetCpp<pkgCacheFile*> +# define PyCdrom_ToCpp GetCpp<pkgCdrom> +# define PyConfiguration_ToCpp GetCpp<Configuration*> +# define PyDepCache_ToCpp GetCpp<pkgDepCache*> +# define PyDependency_ToCpp GetCpp<pkgCache::DepIterator> +# define PyDependencyList_ToCpp GetCpp<RDepListStruct> // TODO +# define PyDescription_ToCpp GetCpp<pkgCache::DescIterator> +# define PyGroup_ToCpp GetCpp<pkgCache::GrpIterator> +# define PyHashes_ToCpp GetCpp<Hashes> +# define PyHashString_ToCpp GetCpp<HashString*> +# define PyMetaIndex_ToCpp GetCpp<metaIndex*> +# define PyPackage_ToCpp GetCpp<pkgCache::PkgIterator> +# define PyPackageFile_ToCpp GetCpp<pkgCache::PkgFileIterator> +# define PyIndexFile_ToCpp GetCpp<pkgIndexFile*> +# define PyOrderList_ToCpp GetCpp<pkgOrderList*> +# define PyPackageList_ToCpp GetCpp<PkgListStruct> // TODO +# define PyPackageManager_ToCpp GetCpp<pkgPackageManager*> +# define PyPackageRecords_ToCpp GetCpp<PkgRecordsStruct> // TODO +# define PyPolicy_ToCpp GetCpp<pkgPolicy*> +# define PyProblemResolver_ToCpp GetCpp<pkgProblemResolver*> +# define PySourceList_ToCpp GetCpp<pkgSourceList*> +# define PySourceRecords_ToCpp GetCpp<PkgSrcRecordsStruct> // TODO +# define PyTagFile_ToCpp GetCpp<pkgTagFile> +# define PyTagSection_ToCpp GetCpp<pkgTagSection> +# define PyVersion_ToCpp GetCpp<pkgCache::VerIterator> + +PyObject* PyAcquire_FromCpp(pkgAcquire *fetcher, bool Delete, PyObject *Owner); +PyObject* PyAcquireFile_FromCpp(pkgAcqFile* const &obj, bool Delete, PyObject *Owner); +PyObject* PyAcquireItem_FromCpp(pkgAcquire::Item* const &obj, bool Delete, PyObject *Owner); +PyObject* PyAcquireItemDesc_FromCpp(pkgAcquire::ItemDesc* const &obj, bool Delete, PyObject *Owner); +PyObject* PyAcquireWorker_FromCpp(pkgAcquire::Worker* const &obj, bool Delete, PyObject *Owner); +PyObject* PyActionGroup_FromCpp(pkgDepCache::ActionGroup* const &obj, bool Delete, PyObject *Owner); +PyObject* PyCache_FromCpp(pkgCache* const &obj, bool Delete, PyObject *Owner); +PyObject* PyCacheFile_FromCpp(pkgCacheFile* const &obj, bool Delete, PyObject *Owner); +PyObject* PyCdrom_FromCpp(pkgCdrom const &obj, bool Delete, PyObject *Owner); +PyObject* PyConfiguration_FromCpp(Configuration* const &obj, bool Delete, PyObject *Owner); +PyObject* PyDepCache_FromCpp(pkgDepCache* const &obj, bool Delete, PyObject *Owner); +PyObject* PyDependency_FromCpp(pkgCache::DepIterator const &obj, bool Delete, PyObject *Owner); +//PyObject* PyDependencyList_FromCpp(RDepListStruct const &obj, bool Delete, PyObject *Owner); +PyObject* PyDescription_FromCpp(pkgCache::DescIterator const &obj, bool Delete, PyObject *Owner); +PyObject* PyHashes_FromCpp(Hashes const &obj, bool Delete, PyObject *Owner); +PyObject* PyHashString_FromCpp(HashString* const &obj, bool Delete, PyObject *Owner); +PyObject* PyMetaIndex_FromCpp(metaIndex* const &obj, bool Delete, PyObject *Owner); +PyObject* PyPackage_FromCpp(pkgCache::PkgIterator const &obj, bool Delete, PyObject *Owner); +PyObject* PyGroup_FromCpp(pkgCache::GrpIterator const &obj, bool Delete, PyObject *Owner); +PyObject* PyIndexFile_FromCpp(pkgIndexFile* const &obj, bool Delete, PyObject *Owner); +PyObject* PyOrderList_FromCpp(pkgOrderList* const &obj, bool Delete, PyObject *Owner); +PyObject* PyPackageFile_FromCpp(pkgCache::PkgFileIterator const &obj, bool Delete, PyObject *Owner); +//PyObject* PyPackageList_FromCpp(PkgListStruct const &obj, bool Delete, PyObject *Owner); +PyObject* PyPackageManager_FromCpp(pkgPackageManager* const &obj, bool Delete, PyObject *Owner); +//PyObject* PyPackageRecords_FromCpp(PkgRecordsStruct const &obj, bool Delete, PyObject *Owner); +PyObject* PyPolicy_FromCpp(pkgPolicy* const &obj, bool Delete, PyObject *Owner); +PyObject* PyProblemResolver_FromCpp(pkgProblemResolver* const &obj, bool Delete, PyObject *Owner); +PyObject* PySourceList_FromCpp(pkgSourceList* const &obj, bool Delete, PyObject *Owner); +//PyObject* PySourceRecords_FromCpp(PkgSrcRecordsStruct const &obj, bool Delete, PyObject *Owner); +PyObject* PyTagFile_FromCpp(pkgTagFile const &obj, bool Delete, PyObject *Owner); +PyObject* PyTagSection_FromCpp(pkgTagSection const &obj, bool Delete, PyObject *Owner); +PyObject* PyVersion_FromCpp(pkgCache::VerIterator const &obj, bool Delete, PyObject *Owner); + +#include "python-apt.h" +#endif + diff --git a/python/arfile.cc b/python/arfile.cc new file mode 100644 index 0000000..8f623b3 --- /dev/null +++ b/python/arfile.cc @@ -0,0 +1,744 @@ +/* + * arfile.cc - Wrapper around ARArchive and ARArchive::Member. + * + * Copyright 2009 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 "generic.h" +#include "apt_instmodule.h" +#include <apt-pkg/arfile.h> +#include <apt-pkg/error.h> +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/configuration.h> +#include <utime.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <array> + +static PyObject *armember_get_name(PyObject *self, void *closure) +{ + return CppPyPath(GetCpp<ARArchive::Member*>(self)->Name); +} + +static PyObject *armember_get_mtime(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->MTime); +} + +static PyObject *armember_get_uid(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->UID); +} + +static PyObject *armember_get_gid(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->GID); +} + +static PyObject *armember_get_mode(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Mode); +} + +static PyObject *armember_get_size(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Size); +} + +static PyObject *armember_get_start(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Start); +} + +static PyObject *armember_repr(PyObject *self) +{ + return PyString_FromFormat("<%s object: name:'%s'>", + self->ob_type->tp_name, + GetCpp<ARArchive::Member*>(self)->Name.c_str()); +} + +static PyGetSetDef armember_getset[] = { + {"gid",armember_get_gid,0,"The group id of the owner."}, + {"mode",armember_get_mode,0,"The mode of the file."}, + {"mtime",armember_get_mtime,0,"Last time of modification."}, + {"name",armember_get_name,0,"The name of the file."}, + {"size",armember_get_size,0,"The size of the files."}, + {"start",armember_get_start,0, + "The offset in the archive where the file starts."}, + {"uid",armember_get_uid,0,"The user ID of the owner."}, + {NULL} +}; + +static const char *armember_doc = + "Represent a single file within an AR archive. For\n" + "Debian packages this can be e.g. control.tar.gz. This class provides\n" + "information about this file, such as the mode and size."; +PyTypeObject PyArMember_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.ArMember", // tp_name + sizeof(CppPyObject<ARArchive::Member*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<ARArchive::Member*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + armember_repr, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + armember_doc, // tp_doc + CppTraverse<ARArchive::Member*>,// tp_traverse + CppClear<ARArchive::Member*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + armember_getset, // tp_getset +}; + + +static const char *filefd_doc= + "Internal helper type, representing a FileFd."; +PyTypeObject PyFileFd_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.__FileFd" , // tp_name + sizeof(CppPyObject<FileFd>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<FileFd>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + filefd_doc, // tp_doc + CppTraverse<FileFd>, // tp_traverse + CppClear<FileFd>, // tp_clear +}; + + +// We just add an inline method and should thus be ABI compatible in a way that +// we can simply cast ARArchive instances to PyARArchiveHack. +class PyARArchiveHack : public ARArchive +{ +public: + inline Member *Members() { + return List; + } +}; + +struct PyArArchiveObject : public CppPyObject<PyARArchiveHack*> { + CppPyObject<FileFd> *Fd; +}; + +static const char *ararchive_getmember_doc = + "getmember(name: str) -> ArMember\n\n" + "Return an ArMember object for the member given by 'name'. Raise\n" + "LookupError if there is no ArMember with the given name."; +static PyObject *ararchive_getmember(PyArArchiveObject *self, PyObject *arg) +{ + PyApt_Filename name; + CppPyObject<ARArchive::Member*> *ret; + if (!name.init(arg)) + return 0; + + const ARArchive::Member *member = self->Object->FindMember(name); + if (!member) { + PyErr_Format(PyExc_LookupError,"No member named '%s'",name.path); + return 0; + } + + // Create our object. + ret = CppPyObject_NEW<ARArchive::Member*>(self,&PyArMember_Type); + ret->Object = const_cast<ARArchive::Member*>(member); + ret->NoDelete = true; + return ret; +} + +static const char *ararchive_extractdata_doc = + "extractdata(name: str) -> bytes\n\n" + "Return the contents of the member, as a bytes object. Raise\n" + "LookupError if there is no ArMember with the given name."; +static PyObject *ararchive_extractdata(PyArArchiveObject *self, PyObject *args) +{ + PyApt_Filename name; + if (PyArg_ParseTuple(args, "O&:extractdata", PyApt_Filename::Converter, &name) == 0) + return 0; + const ARArchive::Member *member = self->Object->FindMember(name); + if (!member) { + PyErr_Format(PyExc_LookupError,"No member named '%s'",name.path); + return 0; + } + if (member->Size > SIZE_MAX) { + PyErr_Format(PyExc_MemoryError, + "Member '%s' is too large to read into memory",name.path); + return 0; + } + if (!self->Fd->Object.Seek(member->Start)) + return HandleErrors(); + + char* value; + try { + value = new char[member->Size]; + } catch (std::bad_alloc&) { + PyErr_Format(PyExc_MemoryError, + "Member '%s' is too large to read into memory",name.path); + return 0; + } + self->Fd->Object.Read(value, member->Size, true); + PyObject *result = PyBytes_FromStringAndSize(value, member->Size); + delete[] value; + return result; +} + +// Helper class to close the FD automatically. +class IntFD { + public: + int fd; + inline operator int() { return fd; }; + inline IntFD(int fd): fd(fd) { }; + inline ~IntFD() { close(fd); }; +}; + +static PyObject *_extract(FileFd &Fd, const ARArchive::Member *member, + const char *dir) +{ + if (!Fd.Seek(member->Start)) + return HandleErrors(); + + std::string outfile_str = flCombine(dir,member->Name); + char *outfile = (char*)outfile_str.c_str(); + + // We are not using FileFd here, because we want to raise OSErrror with + // the correct errno and filename. IntFD's are closed automatically. + IntFD outfd(open(outfile, O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, + member->Mode)); + if (outfd == -1) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, outfile); + if (fchmod(outfd, member->Mode) == -1) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, outfile); + if (fchown(outfd, member->UID, member->GID) != 0 && errno != EPERM) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, outfile); + + // Read 4 KiB from the file, until all of the file is read. Deallocated + // automatically when the function returns. + std::array<char, 4096> value; + unsigned long long size = member->Size; + unsigned long long read = 4096; + while (size > 0) { + if (size < read) + read = size; + if (!Fd.Read(value.data(), read, true)) + return HandleErrors(); + if (write(outfd, value.data(), read) != (signed long long)read) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, outfile); + size -= read; + } + utimbuf time = {static_cast<time_t>(member->MTime), + static_cast<time_t>(member->MTime)}; + if (utime(outfile,&time) == -1) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, outfile); + Py_RETURN_TRUE; +} + +static const char *ararchive_extract_doc = + "extract(name: str[, target: str]) -> bool\n\n" + "Extract the member given by 'name' into the directory given\n" + "by 'target'. If the extraction fails, raise OSError. In case\n" + "of success, return True if the file owner could be set or\n" + "False if this was not possible. If the requested member\n" + "does not exist, raise LookupError."; +static PyObject *ararchive_extract(PyArArchiveObject *self, PyObject *args) +{ + PyApt_Filename name; + PyApt_Filename target; + + target = ""; + if (PyArg_ParseTuple(args, "O&|O&:extract", PyApt_Filename::Converter, &name, PyApt_Filename::Converter, &target) == 0) + return 0; + + const ARArchive::Member *member = self->Object->FindMember(name); + + if (!member) { + PyErr_Format(PyExc_LookupError,"No member named '%s'",name.path); + return 0; + } + return _extract(self->Fd->Object, member, target); +} + +static const char *ararchive_extractall_doc = + "extractall([target: str]) -> bool\n\n" + "Extract all archive contents into the directory given by 'target'. If\n" + "the extraction fails, raise an error. Otherwise, return True if the\n" + "owner could be set or False if the owner could not be changed."; + +static PyObject *ararchive_extractall(PyArArchiveObject *self, PyObject *args) +{ + PyApt_Filename target; + target = ""; + if (PyArg_ParseTuple(args, "|O&:extractall", PyApt_Filename::Converter, &target) == 0) + return 0; + + const ARArchive::Member *member = self->Object->Members(); + + do { + if (_extract(self->Fd->Object, member, target) == 0) + return 0; + } while ((member = member->Next)); + Py_RETURN_TRUE; +} + +static const char *ararchive_gettar_doc = + "gettar(name: str, comp: str) -> TarFile\n\n" + "Return a TarFile object for the member given by 'name' which will be\n" + "decompressed using the compression algorithm given by 'comp'.\n" + "This is almost equal to:\n\n" + " member = arfile.getmember(name)\n" + " tarfile = TarFile(file, member.start, member.size, 'gzip')'\n\n" + "It just opens a new TarFile on the given position in the stream."; +static PyObject *ararchive_gettar(PyArArchiveObject *self, PyObject *args) +{ + PyApt_Filename name; + const char *comp; + if (PyArg_ParseTuple(args, "O&s:gettar", PyApt_Filename::Converter, &name, &comp) == 0) + return 0; + + const ARArchive::Member *member = self->Object->FindMember(name); + if (!member) { + PyErr_Format(PyExc_LookupError,"No member named '%s'",name.path); + return 0; + } + + PyTarFileObject *tarfile = (PyTarFileObject*)CppPyObject_NEW<ExtractTar*>(self->Fd,&PyTarFile_Type); + new (&tarfile->Fd) FileFd(self->Fd->Object.Fd()); + tarfile->min = member->Start; + tarfile->Object = new ExtractTar(self->Fd->Object, member->Size, comp); + return HandleErrors(tarfile); +} + +static const char *ararchive_getmembers_doc = + "getmembers() -> list\n\n" + "Return a list of all members in the archive."; +static PyObject *ararchive_getmembers(PyArArchiveObject *self) +{ + PyObject *list = PyList_New(0); + ARArchive::Member *member = self->Object->Members(); + do { + CppPyObject<ARArchive::Member*> *ret; + ret = CppPyObject_NEW<ARArchive::Member*>(self,&PyArMember_Type); + ret->Object = member; + ret->NoDelete = true; + PyList_Append(list, ret); + Py_DECREF(ret); + } while ((member = member->Next)); + return list; +} + +static const char *ararchive_getnames_doc = + "getnames() -> list\n\n" + "Return a list of the names of all members in the archive."; +static PyObject *ararchive_getnames(PyArArchiveObject *self) +{ + PyObject *list = PyList_New(0); + ARArchive::Member *member = self->Object->Members(); + do { + PyObject *item = CppPyString(member->Name); + PyList_Append(list, item); + Py_DECREF(item); + } while ((member = member->Next)); + return list; +} + +// Just run getmembers() and return an iterator over the list. +static PyObject *ararchive_iter(PyArArchiveObject *self) { + PyObject *members = ararchive_getmembers(self); + PyObject *iter = PyObject_GetIter(members); + Py_DECREF(members); + return iter; +} + +static PyMethodDef ararchive_methods[] = { + {"getmember",(PyCFunction)ararchive_getmember,METH_O, + ararchive_getmember_doc}, + {"gettar",(PyCFunction)ararchive_gettar,METH_VARARGS, + ararchive_gettar_doc}, + {"extractdata",(PyCFunction)ararchive_extractdata,METH_VARARGS, + ararchive_extractdata_doc}, + {"extract",(PyCFunction)ararchive_extract,METH_VARARGS, + ararchive_extract_doc}, + {"extractall",(PyCFunction)ararchive_extractall,METH_VARARGS, + ararchive_extractall_doc}, + {"getmembers",(PyCFunction)ararchive_getmembers,METH_NOARGS, + ararchive_getmembers_doc}, + {"getnames",(PyCFunction)ararchive_getnames,METH_NOARGS, + ararchive_getnames_doc}, + {NULL} +}; + +static PyObject *ararchive_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + PyObject *file; + PyApt_Filename filename; + int fileno; + if (PyArg_ParseTuple(args,"O:__new__",&file) == 0) + return 0; + + PyApt_UniqueObject<PyArArchiveObject> self(NULL); + // We receive a filename. + if (filename.init(file)) { + self.reset((PyArArchiveObject*) CppPyObject_NEW<ARArchive*>(0,type)); + self->Fd = CppPyObject_NEW<FileFd>(NULL, &PyFileFd_Type); + new (&self->Fd->Object) FileFd(filename,FileFd::ReadOnly); + } + // We receive a file object. + else if ((fileno = PyObject_AsFileDescriptor(file)) != -1) { + // Clear the error set by PyObject_AsString(). + PyErr_Clear(); + self.reset((PyArArchiveObject*) CppPyObject_NEW<ARArchive*>(NULL,type)); + self->Fd = CppPyObject_NEW<FileFd>(file, &PyFileFd_Type); + new (&self->Fd->Object) FileFd(fileno,false); + } + else { + return 0; + } + self->Object = (PyARArchiveHack*)new ARArchive(self->Fd->Object); + if (_error->PendingError() == true) + return HandleErrors(); + return self.release(); +} + +static int ararchive_traverse(PyObject *_self, visitproc visit, void* arg) +{ + PyArArchiveObject *self = (PyArArchiveObject*)_self; + Py_VISIT(self->Fd); + return CppTraverse<ARArchive*>(self, visit, arg); +} + +static int ararchive_clear(PyObject *_self) +{ + PyArArchiveObject *self = (PyArArchiveObject*)_self; + Py_CLEAR(self->Fd); + return CppClear<ARArchive*>(self); +} + +static void ararchive_dealloc(PyObject *self) +{ + ararchive_clear(self); + CppDeallocPtr<ARArchive*>(self); +} + +// Return bool or -1 (exception). +static int ararchive_contains(PyObject *self, PyObject *arg) +{ + PyApt_Filename name; + if (!name.init(arg)) + return -1; + return (GetCpp<ARArchive*>(self)->FindMember(name) != 0); +} + +static PySequenceMethods ararchive_as_sequence = { + 0,0,0,0,0,0,0,ararchive_contains,0,0 +}; + +static PyMappingMethods ararchive_as_mapping = { + 0,(PyCFunction)ararchive_getmember,0 +}; + +static const char *ararchive_doc = + "ArArchive(file: str/int/file)\n\n" + "Represent an archive in the 4.4 BSD ar format,\n" + "which is used for e.g. deb packages.\n\n" + "The parameter 'file' may be a string specifying the path of a file, or\n" + "a file-like object providing the fileno() method. It may also be an int\n" + "specifying a file descriptor (returned by e.g. os.open()).\n" + "The recommended way of using it is to pass in the path to the file."; + +PyTypeObject PyArArchive_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.ArArchive", // tp_name + sizeof(PyArArchiveObject), // tp_basicsize + 0, // tp_itemsize + // Methods + ararchive_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &ararchive_as_sequence, // tp_as_sequence + &ararchive_as_mapping, // 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 + Py_TPFLAGS_HAVE_GC, + ararchive_doc, // tp_doc + ararchive_traverse, // tp_traverse + ararchive_clear, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + (getiterfunc)ararchive_iter, // tp_iter + 0, // tp_iternext + ararchive_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 + ararchive_new // tp_new +}; + +/** + * Representation of a Debian package. + * + * This does not resemble debDebFile in apt-inst, but instead is a subclass + * of ArFile which adds properties for the control.tar.$compression and + * data.tar.$compression members which return TarFile objects. It also adds + * a descriptor 'version' which returns the content of 'debian-binary'. + * + * We are using it this way as it seems more natural to represent this special + * kind of AR archive as an AR archive with some extras. + */ +struct PyDebFileObject : PyArArchiveObject { + PyObject *data; + PyObject *control; + PyObject *debian_binary; +}; + +static PyObject *debfile_get_data(PyDebFileObject *self) +{ + return Py_INCREF(self->data), self->data; +} + +static PyObject *debfile_get_control(PyDebFileObject *self) +{ + return Py_INCREF(self->control), self->control; +} + +static PyObject *debfile_get_debian_binary(PyDebFileObject *self) +{ + return Py_INCREF(self->debian_binary), self->debian_binary; +} + +static PyObject *_gettar(PyDebFileObject *self, const ARArchive::Member *m, + const char *comp) +{ + if (!m) + return 0; + PyTarFileObject *tarfile = (PyTarFileObject*)CppPyObject_NEW<ExtractTar*>(self->Fd,&PyTarFile_Type); + new (&tarfile->Fd) FileFd(self->Fd->Object.Fd()); + tarfile->min = m->Start; + tarfile->Object = new ExtractTar(self->Fd->Object, m->Size, comp); + return tarfile; +} + +/* + * Mostly copy-paste from APT + */ +static PyObject *debfile_get_tar(PyDebFileObject *self, const char *Name) +{ + // Get the archive member + const ARArchive::Member *Member = NULL; + const ARArchive &AR = *self->Object; + std::string Compressor; + + std::vector<APT::Configuration::Compressor> compressor = + APT::Configuration::getCompressors(); + for (std::vector<APT::Configuration::Compressor>::const_iterator c = + compressor.begin(); c != compressor.end(); ++c) { + Member = AR.FindMember(std::string(Name).append(c->Extension).c_str()); + if (Member == NULL) + continue; + Compressor = c->Name; + break; + } + + if (Member == NULL) + Member = AR.FindMember(std::string(Name).c_str()); + + if (Member == NULL) { + std::string ext = std::string(Name) + ".{"; + for (std::vector<APT::Configuration::Compressor>::const_iterator c = + compressor.begin(); c != compressor.end(); ++c) { + if (!c->Extension.empty()) + ext.append(c->Extension.substr(1)); + } + ext.append("}"); + _error->Error(("Internal error, could not locate member %s"), + ext.c_str()); + return HandleErrors(); + } + + return _gettar(self, Member, Compressor.c_str()); +} + + +static PyObject *debfile_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyApt_UniqueObject<PyDebFileObject> self((PyDebFileObject*)ararchive_new(type, args, kwds)); + if (self == NULL) + return NULL; + + // DebFile + self->control = debfile_get_tar(self.get(), "control.tar"); + if (self->control == NULL) + return NULL; + + self->data = debfile_get_tar(self.get(), "data.tar"); + if (self->data == NULL) + return NULL; + + const ARArchive::Member *member = self->Object->FindMember("debian-binary"); + if (!member) + return PyErr_Format(PyAptError, "No debian archive, missing %s", + "debian-binary"); + + if (!self->Fd->Object.Seek(member->Start)) + return HandleErrors(); + + char* value = new char[member->Size]; + self->Fd->Object.Read(value, member->Size, true); + self->debian_binary = PyBytes_FromStringAndSize(value, member->Size); + delete[] value; + return self.release(); +} + +static int debfile_traverse(PyObject *_self, visitproc visit, void* arg) +{ + PyDebFileObject *self = (PyDebFileObject*)_self; + Py_VISIT(self->data); + Py_VISIT(self->control); + Py_VISIT(self->debian_binary); + return PyArArchive_Type.tp_traverse(self, visit, arg); +} + +static int debfile_clear(PyObject *_self) { + PyDebFileObject *self = (PyDebFileObject*)_self; + Py_CLEAR(self->data); + Py_CLEAR(self->control); + Py_CLEAR(self->debian_binary); + return PyArArchive_Type.tp_clear(self); +} + +static void debfile_dealloc(PyObject *self) { + debfile_clear((PyDebFileObject *)self); + PyArArchive_Type.tp_dealloc(self); +} + +static PyGetSetDef debfile_getset[] = { + {"control",(getter)debfile_get_control,0, + "The TarFile object associated with the control.tar.gz member."}, + {"data",(getter)debfile_get_data,0, + "The TarFile object associated with the data.tar.$compression member. " + "All apt compression methods are supported. " + }, + {"debian_binary",(getter)debfile_get_debian_binary,0, + "The package version, as contained in debian-binary."}, + {NULL} +}; + +static const char *debfile_doc = + "DebFile(file: str/int/file)\n\n" + "A DebFile object represents a file in the .deb package format.\n\n" + "The parameter 'file' may be a string specifying the path of a file, or\n" + "a file-like object providing the fileno() method. It may also be an int\n" + "specifying a file descriptor (returned by e.g. os.open()).\n" + "The recommended way of using it is to pass in the path to the file.\n\n" + "It differs from ArArchive by providing the members 'control', 'data'\n" + "and 'version' for accessing the control.tar.gz, data.tar.$compression \n" + "(all apt compression methods are supported), and debian-binary members \n" + "in the archive."; + +PyTypeObject PyDebFile_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.DebFile", // tp_name + sizeof(PyDebFileObject), // tp_basicsize + 0, // tp_itemsize + // Methods + debfile_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + debfile_doc, // tp_doc + debfile_traverse, // tp_traverse + debfile_clear, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + debfile_getset, // tp_getset + &PyArArchive_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + debfile_new // tp_new +}; diff --git a/python/cache.cc b/python/cache.cc new file mode 100644 index 0000000..81bbb96 --- /dev/null +++ b/python/cache.cc @@ -0,0 +1,1600 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: cache.cc,v 1.5 2003/06/03 03:03:23 mdz Exp $ +/* ###################################################################### + + Cache - Wrapper for the cache related functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/error.h> +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/update.h> + +#include <Python.h> +#include "progress.h" + +class pkgSourceList; + +// must be in sync with pkgCache::DepType in libapt +// it sucks to have it here duplicated, but we get it +// translated from libapt and that is certainly not what +// we want in a programing interface +const char *UntranslatedDepTypes[] = +{ + "", "Depends","PreDepends","Suggests", + "Recommends","Conflicts","Replaces", + "Obsoletes", "Breaks", "Enhances" +}; + + /*}}}*/ + +template<typename T> struct IterListStruct +{ + T Iter; + unsigned long LastIndex; + + IterListStruct(T const &I) : Iter(I), LastIndex(0) {} + IterListStruct() : LastIndex(0) {}; + + bool move(unsigned long Index) { + if ((unsigned)Index >= Count()) + { + PyErr_SetNone(PyExc_IndexError); + return false; + } + + if ((unsigned)Index < LastIndex) + { + LastIndex = 0; + Iter = Begin(); + } + + while ((unsigned)Index > LastIndex) + { + LastIndex++; + Iter++; + if (Iter.end() == true) + { + PyErr_SetNone(PyExc_IndexError); + return false; + } + } + return true; + } + + virtual unsigned Count() = 0; + virtual T Begin() = 0; + +}; + +struct PkgListStruct : public IterListStruct<pkgCache::PkgIterator> { + unsigned Count() { return Iter.Cache()->HeaderP->PackageCount; } + pkgCache::PkgIterator Begin() { return Iter.Cache()->PkgBegin(); } + + PkgListStruct(pkgCache::PkgIterator const &I) { Iter = I; } +}; + +struct GrpListStruct : public IterListStruct<pkgCache::GrpIterator> { + unsigned Count() { return Iter.Cache()->HeaderP->GroupCount; } + pkgCache::GrpIterator Begin() { return Iter.Cache()->GrpBegin(); } + GrpListStruct(pkgCache::GrpIterator const &I) { Iter = I; } +}; + +struct RDepListStruct +{ + pkgCache::DepIterator Iter; + pkgCache::DepIterator Start; + unsigned long LastIndex; + unsigned long Len; + + RDepListStruct(pkgCache::DepIterator const &I) : Iter(I), Start(I), + LastIndex(0) + { + Len = 0; + pkgCache::DepIterator D = I; + for (; D.end() == false; D++) + Len++; + } + RDepListStruct() {abort();}; // G++ Bug.. +}; + +static PyObject *CreateProvides(PyObject *Owner,pkgCache::PrvIterator I) +{ + PyObject *List = PyList_New(0); + for (; I.end() == false; I++) + { + PyObject *Obj; + PyObject *Ver; + Ver = CppPyObject_NEW<pkgCache::VerIterator>(Owner,&PyVersion_Type, + I.OwnerVer()); + Obj = Py_BuildValue("ssN",I.ParentPkg().Name(),I.ProvideVersion(), + Ver); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +// Cache Class /*{{{*/ +// --------------------------------------------------------------------- + +static const char *cache_update_doc = + "update(progress, sources: SourceList, pulse_interval: int) -> bool\n\n" + "Update the index files used by the cache. A call to this method\n" + "does not affect the current Cache object; instead, a new one\n" + "should be created in order to use the changed index files.\n\n" + "The parameter 'progress' can be used to specify an\n" + "apt.progress.base.AcquireProgress() object , which will report\n" + "progress information while the index files are being fetched.\n" + "The parameter 'sources', if provided, is an apt_pkg.SourcesList\n" + "object listing the remote repositories to be used.\n" + "The 'pulse_interval' parameter indicates how long (in microseconds)\n" + "to wait between calls to the pulse() method of the 'progress' object.\n" + "The default is 500000 microseconds."; +static PyObject *PkgCacheUpdate(PyObject *Self,PyObject *Args) +{ + PyObject *pyFetchProgressInst = 0; + PyObject *pySourcesList = 0; + int pulseInterval = 0; + if (PyArg_ParseTuple(Args, "OO!|i", &pyFetchProgressInst, + &PySourceList_Type, &pySourcesList, &pulseInterval) == 0) + return 0; + + PyFetchProgress progress; + progress.setCallbackInst(pyFetchProgressInst); + pkgSourceList *source = GetCpp<pkgSourceList*>(pySourcesList); + bool res = ListUpdate(progress, *source, pulseInterval); + + PyObject *PyRes = PyBool_FromLong(res); + return HandleErrors(PyRes); +} + + +static PyMethodDef PkgCacheMethods[] = +{ + {"update",PkgCacheUpdate,METH_VARARGS,cache_update_doc}, + {} +}; + +static PyObject *PkgCacheGetGroupCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->GroupCount); +} + +static PyObject *PkgCacheGetGroups(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return CppPyObject_NEW<GrpListStruct>(Self,&PyGroupList_Type,Cache->GrpBegin()); +} + +static PyObject *PkgCacheGetPolicy(PyObject *Self, void*) { + PyObject *CacheFilePy = GetOwner<pkgCache*>(Self); + pkgCacheFile *CacheF = GetCpp<pkgCacheFile*>(CacheFilePy); + pkgDepCache *DepCache = (pkgDepCache *)(*CacheF); + + pkgPolicy *Policy = (pkgPolicy *)&DepCache->GetPolicy(); + CppPyObject<pkgPolicy*> *PyPolicy = + CppPyObject_NEW<pkgPolicy*>(Self,&PyPolicy_Type,Policy); + // Policy should not be deleted, it is managed by CacheFile. + PyPolicy->NoDelete = true; + return PyPolicy; +} + +static PyObject *PkgCacheGetPackages(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return CppPyObject_NEW<PkgListStruct>(Self,&PyPackageList_Type,Cache->PkgBegin()); +} + +static PyObject *PkgCacheGetPackageCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber((int)Cache->HeaderP->PackageCount); +} + +static PyObject *PkgCacheGetVersionCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->VersionCount); +} +static PyObject *PkgCacheGetDependsCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->DependsCount); +} + +static PyObject *PkgCacheGetPackageFileCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->PackageFileCount); +} + +static PyObject *PkgCacheGetVerFileCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->VerFileCount); +} + +static PyObject *PkgCacheGetProvidesCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->ProvidesCount); +} + +static PyObject *PkgCacheGetFileList(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + PyObject *List = PyList_New(0); + for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I.end() == false; I++) + { + PyObject *Obj; + Obj = CppPyObject_NEW<pkgCache::PkgFileIterator>(Self,&PyPackageFile_Type,I); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyObject *PkgCacheGetIsMultiArch(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return PyBool_FromLong(Cache->MultiArchCache()); +} + +static PyGetSetDef PkgCacheGetSet[] = { + {"depends_count",PkgCacheGetDependsCount,0, + "The number of apt_pkg.Dependency objects stored in the cache."}, + {"file_list",PkgCacheGetFileList,0, + "A list of apt_pkg.PackageFile objects stored in the cache."}, + {"group_count",PkgCacheGetGroupCount,0, + "The number of apt_pkg.Group objects stored in the cache."}, + {"groups", PkgCacheGetGroups, 0, "A list of Group objects in the cache"}, + {"policy", PkgCacheGetPolicy, 0, "The PkgPolicy for the cache"}, + {"is_multi_arch", PkgCacheGetIsMultiArch, 0, + "Whether the cache supports multi-arch."}, + {"package_count",PkgCacheGetPackageCount,0, + "The number of apt_pkg.Package objects stored in the cache."}, + {"package_file_count",PkgCacheGetPackageFileCount,0, + "The number of apt_pkg.PackageFile objects stored in the cache."}, + {"packages",PkgCacheGetPackages,0, + "A list of apt_pkg.Package objects stored in the cache."}, + {"provides_count",PkgCacheGetProvidesCount,0, + "Number of Provides relations described in the cache."}, + {"ver_file_count",PkgCacheGetVerFileCount,0, + "The number of (Version, PackageFile) relations."}, + {"version_count",PkgCacheGetVersionCount,0, + "The number of apt_pkg.Version objects stored in the cache."}, + {} +}; + +// Helper to call FindPkg(name) or FindPkg(name, architecture) +static pkgCache::PkgIterator CacheFindPkg(PyObject *self, PyObject *arg) +{ + const char *name; + const char *architecture; + pkgCache *cache = GetCpp<pkgCache *>(self); + + name = PyObject_AsString(arg); + + if (name != NULL) + return cache->FindPkg(name); + + PyErr_Clear(); + + if (PyArg_ParseTuple(arg, "ss", &name, &architecture) == 0) { + PyErr_Clear(); + PyErr_Format(PyExc_TypeError, "Expected a string or a pair of strings"); + return pkgCache::PkgIterator(); + } + + return cache->FindPkg(name, architecture); +} + +// Map access, operator [] +static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) +{ + pkgCache::PkgIterator Pkg = CacheFindPkg(Self, Arg); + if (Pkg.end() == true) + { + if (!PyErr_Occurred()) + PyErr_SetObject(PyExc_KeyError,Arg); + return 0; + } + + return CppPyObject_NEW<pkgCache::PkgIterator>(Self,&PyPackage_Type,Pkg); +} + +// Check whether the cache contains a package with a given name. +static int CacheContains(PyObject *Self,PyObject *Arg) +{ + bool res = (CacheFindPkg(Self, Arg).end() == false); + PyErr_Clear(); + return res; +} + +static PyObject *PkgCacheNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *pyCallbackInst = 0; + char *kwlist[] = {"progress", 0}; + + if (PyArg_ParseTupleAndKeywords(Args, kwds, "|O", kwlist, + &pyCallbackInst) == 0) + return 0; + + if (_system == 0) { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + + pkgCacheFile *Cache = new pkgCacheFile(); + + if (pyCallbackInst == Py_None) { + OpProgress Prog; + if (Cache->Open(&Prog,false) == false) + return HandleErrors(); + } else if(pyCallbackInst != 0) { + // sanity check for the progress object, see #497049 + if (PyObject_HasAttrString(pyCallbackInst, "done") != true) { + PyErr_SetString(PyExc_ValueError, + "OpProgress object must implement done()"); + return 0; + } + if (PyObject_HasAttrString(pyCallbackInst, "update") != true) { + PyErr_SetString(PyExc_ValueError, + "OpProgress object must implement update()"); + return 0; + } + PyOpProgress progress; + progress.setCallbackInst(pyCallbackInst); + if (Cache->Open(&progress,false) == false) + return HandleErrors(); + } + else { + OpTextProgress Prog; + if (Cache->Open(&Prog,false) == false) + return HandleErrors(); + } + + // ensure that the states are correct (LP: #659438) + pkgApplyStatus(*Cache); + + CppPyObject<pkgCacheFile*> *CacheFileObj = + CppPyObject_NEW<pkgCacheFile*>(0,&PyCacheFile_Type, Cache); + + CppPyObject<pkgCache *> *CacheObj = + CppPyObject_NEW<pkgCache *>(CacheFileObj,type, + (pkgCache *)(*Cache)); + + // Do not delete the pointer to the pkgCache, it is managed by pkgCacheFile. + CacheObj->NoDelete = true; + Py_DECREF(CacheFileObj); + return CacheObj; +} + +static Py_ssize_t CacheMapLen(PyObject *Self) +{ + return GetCpp<pkgCache*>(Self)->HeaderP->PackageCount; +} + +static char *doc_PkgCache = "Cache([progress]) -> Cache() object.\n\n" + "The APT cache file contains a hash table mapping names of binary\n" + "packages to their metadata. A Cache object is the in-core\n" + "representation of the same. It provides access to APT’s idea of the\n" + "list of available packages.\n" + "The optional parameter *progress* can be used to specify an \n" + "apt.progress.base.OpProgress() object (or similar) which reports\n" + "progress information while the cache is being opened. If this\n" + "parameter is not supplied, the progress will be reported in simple,\n" + "human-readable text to standard output. If it is None, no output\n" + "will be made.\n\n" + "The cache can be used like a mapping from package names to Package\n" + "objects (although only getting items is supported). Instead of a name,\n" + "a tuple of a name and an architecture may be used."; +static PySequenceMethods CacheSeq = {0,0,0,0,0,0,0,CacheContains,0,0}; +static PyMappingMethods CacheMap = {CacheMapLen,CacheMapOp,0}; +PyTypeObject PyCache_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Cache", // tp_name + sizeof(CppPyObject<pkgCache *>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgCache *>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &CacheSeq, // tp_as_sequence + &CacheMap, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_PkgCache, // tp_doc + CppTraverse<pkgCache *>, // tp_traverse + CppClear<pkgCache *>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgCacheMethods, // tp_methods + 0, // tp_members + PkgCacheGetSet, // 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 + PkgCacheNew, // tp_new +}; + /*}}}*/ +// PkgCacheFile Class /*{{{*/ +// --------------------------------------------------------------------- +PyTypeObject PyCacheFile_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "pkgCacheFile", // tp_name + sizeof(CppPyObject<pkgCacheFile*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgCacheFile*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 +}; + +// Package List Class /*{{{*/ +// --------------------------------------------------------------------- +static Py_ssize_t PkgListLen(PyObject *Self) +{ + return GetCpp<PkgListStruct>(Self).Iter.Cache()->HeaderP->PackageCount; +} + +static PyObject *PkgListItem(PyObject *iSelf,Py_ssize_t Index) +{ + PkgListStruct &Self = GetCpp<PkgListStruct>(iSelf); + + if (!Self.move(Index)) + return 0; + return CppPyObject_NEW<pkgCache::PkgIterator>(GetOwner<PkgListStruct>(iSelf),&PyPackage_Type, + Self.Iter); +} + +static PySequenceMethods PkgListSeq = +{ + PkgListLen, + 0, // concat + 0, // repeat + PkgListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +static const char *packagelist_doc = + "A PackageList is an internally used structure to represent\n" + "the 'packages' attribute of apt_pkg.Cache objects in a more\n" + "efficient manner by creating Package objects only when they\n" + "are accessed."; + +PyTypeObject PyPackageList_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageList", // tp_name + sizeof(CppPyObject<PkgListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<PkgListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &PkgListSeq, // 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 | Py_TPFLAGS_HAVE_GC, // tp_flags + packagelist_doc, // tp_doc + CppTraverse<PkgListStruct>, // tp_traverse + CppClear<PkgListStruct>, // tp_clear +}; + +/* The same for groups */ +static Py_ssize_t GrpListLen(PyObject *Self) +{ + return GetCpp<GrpListStruct>(Self).Iter.Cache()->HeaderP->GroupCount; +} + +static PyObject *GrpListItem(PyObject *iSelf,Py_ssize_t Index) +{ + GrpListStruct &Self = GetCpp<GrpListStruct>(iSelf); + + if (!Self.move(Index)) + return 0; + return CppPyObject_NEW<pkgCache::GrpIterator>(GetOwner<GrpListStruct>(iSelf),&PyGroup_Type, + Self.Iter); +} + +static PySequenceMethods GrpListSeq = +{ + GrpListLen, + 0, // concat + 0, // repeat + GrpListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +static const char *grouplist_doc = + "A GroupList is an internally used structure to represent\n" + "the 'groups' attribute of apt_pkg.Cache objects in a more\n" + "efficient manner by creating Group objects only when they\n" + "are accessed."; + +PyTypeObject PyGroupList_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.GroupList", // tp_name + sizeof(CppPyObject<GrpListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<GrpListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &GrpListSeq, // 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 | Py_TPFLAGS_HAVE_GC, // tp_flags + grouplist_doc, // tp_doc + CppTraverse<GrpListStruct>, // tp_traverse + CppClear<GrpListStruct>, // tp_clear +}; + + +#define Owner (GetOwner<pkgCache::PkgIterator>(Self)) +#define MkGet(PyFunc,Ret) static PyObject *PyFunc(PyObject *Self,void*) \ +{ \ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); \ + return Ret; \ +} + +MkGet(PackageGetName,CppPyString(Pkg.Name())) +MkGet(PackageGetArch,CppPyString(Pkg.Arch())) +MkGet(PackageGetRevDependsList,CppPyObject_NEW<RDepListStruct>(Owner, + &PyDependencyList_Type, Pkg.RevDependsList())) +MkGet(PackageGetProvidesList,CreateProvides(Owner,Pkg.ProvidesList())) +MkGet(PackageGetSelectedState,MkPyNumber(Pkg->SelectedState)) +MkGet(PackageGetInstState,MkPyNumber(Pkg->InstState)) +MkGet(PackageGetCurrentState,MkPyNumber(Pkg->CurrentState)) +MkGet(PackageGetID,MkPyNumber(Pkg->ID)) +# +MkGet(PackageGetEssential,PyBool_FromLong((Pkg->Flags & pkgCache::Flag::Essential) != 0)) +MkGet(PackageGetImportant,PyBool_FromLong((Pkg->Flags & pkgCache::Flag::Important) != 0)) +#undef MkGet +#undef Owner + +static const char PackageGetFullName_doc[] = + "get_fullname([pretty: bool = False]) -> str\n\n" + "Get the full name of the package, including the architecture. If\n" + "'pretty' is True, the architecture is omitted for native packages,\n" + "that is, and amd64 apt package on an amd64 system would give 'apt'."; +static PyObject *PackageGetFullName(PyObject *Self,PyObject *Args,PyObject *kwds) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + char pretty = 0; + char *kwlist[] = {"pretty", 0}; + + if (PyArg_ParseTupleAndKeywords(Args, kwds, "|b", kwlist, + &pretty) == 0) + return 0; + + + return CppPyString(Pkg.FullName(pretty)); +} + +static PyObject *PackageGetVersionList(PyObject *Self,void*) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::PkgIterator>(Self); + + PyObject *List = PyList_New(0); + for (pkgCache::VerIterator I = Pkg.VersionList(); I.end() == false; I++) + { + PyObject *Obj; + Obj = CppPyObject_NEW<pkgCache::VerIterator>(Owner,&PyVersion_Type,I); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyObject *PackageGetHasVersions(PyObject *Self,void*) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + return PyBool_FromLong(Pkg.VersionList().end() == false); +} + +static PyObject *PackageGetHasProvides(PyObject *Self,void*) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + return PyBool_FromLong(Pkg.ProvidesList().end() == false); +} + +static PyObject *PackageGetCurrentVer(PyObject *Self,void*) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::PkgIterator>(Self); + if (Pkg->CurrentVer == 0) + { + Py_INCREF(Py_None); + return Py_None; + } + return CppPyObject_NEW<pkgCache::VerIterator>(Owner,&PyVersion_Type, + Pkg.CurrentVer()); +} + + +static PyMethodDef PackageMethods[] = +{ + {"get_fullname",(PyCFunction)PackageGetFullName,METH_VARARGS|METH_KEYWORDS, + PackageGetFullName_doc}, + {} +}; + +static PyGetSetDef PackageGetSet[] = { + {"name",PackageGetName,0, + "The name of the package."}, + {"architecture",PackageGetArch,0, "The architecture of the package."}, + {"rev_depends_list",PackageGetRevDependsList,0, + "An apt_pkg.DependencyList object of all reverse dependencies."}, + {"provides_list",PackageGetProvidesList,0, + "A list of all packages providing this package. The list contains\n" + "tuples in the format (providesname, providesver, version)\n" + "where 'version' is an apt_pkg.Version object."}, + {"selected_state",PackageGetSelectedState,0, + "The state of the selection, which can be compared against the constants\n" + "SELSTATE_DEINSTALL, SELSTATE_HOLD, SELSTATE_INSTALL, SELSTATE_PURGE,\n" + "SELSTATE_UNKNOWN of the apt_pkg module."}, + {"inst_state",PackageGetInstState,0, + "The state of the install, which be compared against the constants\n" + "INSTSTATE_HOLD, INSTSTATE_HOLD_REINSTREQ, INSTSTATE_OK,\n" + "INSTSTATE_REINSTREQ of the apt_pkg module."}, + {"current_state",PackageGetCurrentState,0, + "The current state, which can be compared against the constants\n" + "CURSTATE_CONFIG_FILES, CURSTATE_HALF_CONFIGURED,\n" + "CURSTATE_HALF_INSTALLED, CURSTATE_INSTALLED, CURSTATE_NOT_INSTALLED,\n" + "CURSTATE_UNPACKED of the apt_pkg module."}, + {"id",PackageGetID,0, + "The numeric ID of the package"}, + {"essential",PackageGetEssential,0, + "Boolean value determining whether the package is essential."}, + {"important",PackageGetImportant,0, + "Boolean value determining whether the package has the 'important'\n" + "flag set ('Important: yes' in the Packages file). No longer used."}, + {"version_list",PackageGetVersionList,0, + "A list of all apt_pkg.Version objects for this package."}, + {"current_ver",PackageGetCurrentVer,0, + "The version of the package currently installed or None."}, + {"has_versions",PackageGetHasVersions,0, + "Whether the package has at least one version in the cache."}, + {"has_provides",PackageGetHasProvides,0, + "Whether the package is provided by at least one other package."}, + {} +}; + +static PyObject *PackageRepr(PyObject *Self) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + return PyString_FromFormat("<%s object: name:'%s' id:%u>", Self->ob_type->tp_name, + Pkg.Name(), Pkg->ID); +} + +static const char *package_doc = + "Represent a package. A package is uniquely identified by its name\n" + "and each package can have zero or more versions which can be\n" + "accessed via the version_list property. Packages can be installed\n" + "and removed by apt_pkg.DepCache."; + +PyTypeObject PyPackage_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Package", // tp_name + sizeof(CppPyObject<pkgCache::PkgIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCache::PkgIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + PackageRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + package_doc, // tp_doc + CppTraverse<pkgCache::PkgIterator>, // tp_traverse + CppClear<pkgCache::PkgIterator>,// tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PackageMethods, // tp_methods + 0, // tp_members + PackageGetSet, // tp_getset +}; + +#define Description_MkGet(PyFunc,Ret) static PyObject \ + *PyFunc(PyObject *Self,void*) { \ + pkgCache::DescIterator &Desc = GetCpp<pkgCache::DescIterator>(Self); \ + return Ret; } + +Description_MkGet(DescriptionGetLanguageCode, + CppPyString(Desc.LanguageCode())) +Description_MkGet(DescriptionGetMd5,CppPyString(Desc.md5())) +#undef Description_MkGet + +static PyObject *DescriptionGetFileList(PyObject *Self,void*) +{ + pkgCache::DescIterator &Desc = GetCpp<pkgCache::DescIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DescIterator>(Self); + + /* The second value in the tuple is the index of the VF item. If the + user wants to request a lookup then that number will be used. + Maybe later it can become an object. */ + PyObject *List = PyList_New(0); + for (pkgCache::DescFileIterator I = Desc.FileList(); I.end() == false; I++) + { + PyObject *DescFile; + PyObject *Obj; + DescFile = CppPyObject_NEW<pkgCache::PkgFileIterator>(Owner,&PyPackageFile_Type,I.File()); + Obj = Py_BuildValue("NN",DescFile,MkPyNumber(I.Index())); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyGetSetDef DescriptionGetSet[] = { + {"language_code",DescriptionGetLanguageCode,0, + "The language code of the description. Empty string for untranslated\n" + "descriptions."}, + {"md5",DescriptionGetMd5,0, + "The MD5 hash of the description."}, + {"file_list",DescriptionGetFileList,0, + "A list of all apt_pkg.PackageFile objects related to this description."}, + {} +}; + +static PyObject *DescriptionRepr(PyObject *Self) +{ + pkgCache::DescIterator &Desc = GetCpp<pkgCache::DescIterator>(Self); + return PyString_FromFormat("<%s object: language_code:'%s' md5:'%s' ", + Self->ob_type->tp_name, Desc.LanguageCode(), + Desc.md5()); +} + +static const char *description_doc = + "Represent a package description and some attributes. Needed for\n" + "things like translated descriptions."; + +PyTypeObject PyDescription_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Description", // tp_name + sizeof(CppPyObject<pkgCache::DescIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCache::DescIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + DescriptionRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + description_doc, // tp_doc + CppTraverse<pkgCache::DescIterator>, // tp_traverse + CppClear<pkgCache::DescIterator>,// tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + DescriptionGetSet, // tp_getset +}; + /*}}}*/ +// Version Class /*{{{*/ +// --------------------------------------------------------------------- + +/* This is the simple depends result, the elements are split like + ParseDepends does */ +static PyObject *MakeDepends(PyObject *Owner,pkgCache::VerIterator &Ver, + bool AsObj) +{ + PyObject *Dict = PyDict_New(); + PyObject *LastDep = 0; + unsigned LastDepType = 0; + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;) + { + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); + + // Switch/create a new dict entry + if (LastDepType != Start->Type || LastDep != 0) + { + PyObject *Dep = CppPyString(UntranslatedDepTypes[Start->Type]); + LastDepType = Start->Type; + LastDep = PyDict_GetItem(Dict,Dep); + if (LastDep == 0) + { + LastDep = PyList_New(0); + PyDict_SetItem(Dict,Dep,LastDep); + Py_DECREF(LastDep); + } + Py_DECREF(Dep); + } + + PyObject *OrGroup = PyList_New(0); + while (1) + { + PyObject *Obj; + if (AsObj == true) + Obj = CppPyObject_NEW<pkgCache::DepIterator>(Owner,&PyDependency_Type, + Start); + else + { + if (Start->Version == 0) + Obj = Py_BuildValue("sss", + Start.TargetPkg().Name(), + "", + Start.CompType()); + else + Obj = Py_BuildValue("sss", + Start.TargetPkg().Name(), + Start.TargetVer(), + Start.CompType()); + } + PyList_Append(OrGroup,Obj); + Py_DECREF(Obj); + + if (Start == End) + break; + Start++; + } + + PyList_Append(LastDep,OrGroup); + Py_DECREF(OrGroup); + } + + return Dict; +} + +static inline pkgCache::VerIterator Version_GetVer(PyObject *Self) { + return GetCpp<pkgCache::VerIterator>(Self); +} + +// Version attributes. +static PyObject *VersionGetVerStr(PyObject *Self, void*) { + return CppPyString(Version_GetVer(Self).VerStr()); +} +static PyObject *VersionGetSection(PyObject *Self, void*) { + return CppPyString(Version_GetVer(Self).Section()); +} +static PyObject *VersionGetArch(PyObject *Self, void*) { + return CppPyString(Version_GetVer(Self).Arch()); +} +static PyObject *VersionGetFileList(PyObject *Self, void*) { + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + PyObject *List = PyList_New(0); + for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; I++) + { + PyObject *PkgFile; + PyObject *Obj; + PkgFile = CppPyObject_NEW<pkgCache::PkgFileIterator>(Owner,&PyPackageFile_Type,I.File()); + Obj = Py_BuildValue("NN",PkgFile,MkPyNumber(I.Index())); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyObject *VersionGetDependsListStr(PyObject *Self, void*) { + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + return MakeDepends(Owner,Ver,false); +} +static PyObject *VersionGetDependsList(PyObject *Self, void*) { + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + return MakeDepends(Owner,Ver,true); +} +static PyObject *VersionGetParentPkg(PyObject *Self, void*) { + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + return CppPyObject_NEW<pkgCache::PkgIterator>(Owner,&PyPackage_Type, + Version_GetVer(Self).ParentPkg()); +} +static PyObject *VersionGetProvidesList(PyObject *Self, void*) { + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + return CreateProvides(Owner,Version_GetVer(Self).ProvidesList()); +} +static PyObject *VersionGetSize(PyObject *Self, void*) { + return MkPyNumber(Version_GetVer(Self)->Size); +} +static PyObject *VersionGetInstalledSize(PyObject *Self, void*) { + return MkPyNumber(Version_GetVer(Self)->InstalledSize); +} +static PyObject *VersionGetHash(PyObject *Self, void*) { + return MkPyNumber(Version_GetVer(Self)->Hash); +} +static PyObject *VersionGetID(PyObject *Self, void*) { + return MkPyNumber(Version_GetVer(Self)->ID); +} +static PyObject *VersionGetPriority(PyObject *Self, void*) { + return MkPyNumber(Version_GetVer(Self)->Priority); +} +static PyObject *VersionGetPriorityStr(PyObject *Self, void*) { + return CppPyString(Version_GetVer(Self).PriorityType()); +} +static PyObject *VersionGetDownloadable(PyObject *Self, void*) { + return PyBool_FromLong(Version_GetVer(Self).Downloadable()); +} +static PyObject *VersionGetTranslatedDescription(PyObject *Self, void*) { + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + return CppPyObject_NEW<pkgCache::DescIterator>(Owner, + &PyDescription_Type, + Ver.TranslatedDescription()); +} + +static PyObject *VersionGetIsSecurityUpdate(PyObject *Self, void*) { + return PyBool_FromLong(Version_GetVer(Self).IsSecurityUpdate()); +} + +static PyObject *VersionGetMultiArch(PyObject *Self, void*) +{ + return MkPyNumber(Version_GetVer(Self)->MultiArch); +} + +#if 0 // FIXME: enable once pkgSourceList is stored somewhere +static PyObject *VersionGetIsTrusted(PyObject *Self, void*) { + else if (strcmp("IsTrusted", Name) == 0) + { + pkgSourceList Sources; + Sources.ReadMainList(); + for(pkgCache::VerFileIterator i = Ver.FileList(); !i.end(); i++) + { + pkgIndexFile *index; + if(Sources.FindIndex(i.File(), index) && !index->IsTrusted()) + Py_RETURN_FALSE; + } + Py_RETURN_TRUE; + } +} +#endif + +#define NOTNULL(x) (x ? x : "") + +static PyObject *VersionRepr(PyObject *Self) +{ + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + return PyString_FromFormat("<%s object: Pkg:'%s' Ver:'%s' Section:'%s' " + " Arch:'%s' Size:%lu ISize:%lu Hash:%u ID:%u " + "Priority:%u>", Self->ob_type->tp_name, + Ver.ParentPkg().Name(), Ver.VerStr(), + NOTNULL(Ver.Section()), NOTNULL(Ver.Arch()), + (unsigned long)Ver->Size, + (unsigned long)Ver->InstalledSize, + Ver->Hash, Ver->ID, Ver->Priority); +} +#undef NOTNULL + +static PyObject *version_richcompare(PyObject *obj1, PyObject *obj2, int op) +{ + if (!PyVersion_Check(obj2)) + return Py_INCREF(Py_NotImplemented), Py_NotImplemented; + + const pkgCache::VerIterator &a = GetCpp<pkgCache::VerIterator>(obj1); + const pkgCache::VerIterator &b = GetCpp<pkgCache::VerIterator>(obj2); + const int comparison = _system->VS->CmpVersion(a.VerStr(), b.VerStr()); + switch (op) { + case Py_LT: return PyBool_FromLong(comparison < 0); + case Py_LE: return PyBool_FromLong(comparison <= 0); + case Py_EQ: return PyBool_FromLong(comparison == 0); + case Py_NE: return PyBool_FromLong(comparison != 0); + case Py_GE: return PyBool_FromLong(comparison >= 0); + case Py_GT: return PyBool_FromLong(comparison > 0); + default: return NULL; // should not happen. + } +} + +static PyGetSetDef VersionGetSet[] = { + {"arch",VersionGetArch,0, + "The architecture of this specific version of the package."}, + {"depends_list",VersionGetDependsList,0, + "A dictionary mapping dependency types to lists (A) of lists (B) of\n" + "apt_pkg.Dependency objects. The lists (B) represent or dependencies\n" + "like 'a || b'."}, + {"depends_list_str",VersionGetDependsListStr,0, + "Same as depends_list, except that the apt_pkg.Dependency objects\n" + "are 3-tuples of the form (name, version, operator); where operator\n" + "is one of '<', '<=', '=', '>=', '>'."}, + {"downloadable",VersionGetDownloadable,0, + "Whether the version can be downloaded."}, + {"file_list",VersionGetFileList,0, + "A list of tuples (packagefile: apt_pkg.PackageFile, index: int) for the\n" + "PackageFile objects related to this package. The index can be used\n" + "to retrieve the record of this package version."}, + {"hash",VersionGetHash,0, + "The numeric hash of the version used in the internal storage."}, + {"id",VersionGetID,0, + "The numeric ID of the package."}, + {"installed_size",VersionGetInstalledSize,0, + "The installed size of this package version."}, + {"multi_arch",VersionGetMultiArch,0, + "Multi-arch state of this package, as an integer. See\n" + "the various MULTI_ARCH_* members."}, + {"parent_pkg",VersionGetParentPkg,0, + "The parent package of this version."}, + {"priority",VersionGetPriority,0, + "The priority of the package as an integer, which can be compared to\n" + "the constants PRI_EXTRA, PRI_IMPORTANT, PRI_OPTIONAL, PRI_REQUIRED,\n" + "PRI_STANDARD of the apt_pkg module."}, + {"priority_str",VersionGetPriorityStr,0, + "The priority of the package, as a string."}, + {"provides_list",VersionGetProvidesList,0, + "A list of all packages provided by this version. The list contains\n" + "tuples in the format (providesname, providesver, version)\n" + "where 'version' is an apt_pkg.Version object."}, + {"section",VersionGetSection,0, + "The section of this package version."}, + {"size",VersionGetSize,0, + "The size of the package file."}, + {"translated_description",VersionGetTranslatedDescription,0, + "An apt_pkg.Description object for the translated description if\n" + "available or the untranslated fallback."}, + {"is_security_update",VersionGetIsSecurityUpdate,0, + "Whether this version is a security update."}, + {"ver_str",VersionGetVerStr,0, + "The version string."}, + {} +}; + +PyTypeObject PyVersion_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Version", // tp_name + sizeof(CppPyObject<pkgCache::VerIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCache::VerIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + VersionRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + "Version Object", // tp_doc + CppTraverse<pkgCache::VerIterator>, // tp_traverse + CppClear<pkgCache::VerIterator>,// tp_clear + version_richcompare, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + VersionGetSet, // tp_getset +}; + + /*}}}*/ + +// PackageFile Class /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *PackageFile_GetFileName(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyPath(File.FileName()); +} + +static PyObject *PackageFile_GetArchive(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Archive()); +} + +static PyObject *PackageFile_GetComponent(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Component()); +} + +static PyObject *PackageFile_GetVersion(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Version()); +} + +static PyObject *PackageFile_GetOrigin(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Origin()); +} + +static PyObject *PackageFile_GetLabel(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Label()); +} + +static PyObject *PackageFile_GetArchitecture(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Architecture()); +} + +static PyObject *PackageFile_GetCodename(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Codename()); +} + +static PyObject *PackageFile_GetSite(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.Site()); +} + +static PyObject *PackageFile_GetIndexType(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return CppPyString(File.IndexType()); +} +static PyObject *PackageFile_GetSize(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return MkPyNumber(File->Size); +} + +static PyObject *PackageFile_GetNotSource(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return PyBool_FromLong((File->Flags & pkgCache::Flag::NotSource) != 0); +} +static PyObject *PackageFile_GetNotAutomatic(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return PyBool_FromLong((File->Flags & pkgCache::Flag::NotAutomatic) != 0); +} + +static PyObject *PackageFile_GetID(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return MkPyNumber(File->ID); +} + +#define S(s) (s == NULL ? "" : s) +static PyObject *PackageFileRepr(PyObject *Self) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + + return PyString_FromFormat("<%s object: filename:'%s'" + " a=%s,c=%s,v=%s,o=%s,l=%s arch='%s' site='%s'" + " IndexType='%s' Size=%lu ID:%u>", + Self->ob_type->tp_name, File.FileName(), + S(File.Archive()), + S(File.Component()),S(File.Version()), + S(File.Origin()),S(File.Label()), + S(File.Architecture()),S(File.Site()), + S(File.IndexType()),File->Size,File->ID); +} +#undef S + +static PyGetSetDef PackageFileGetSet[] = { + {"architecture",PackageFile_GetArchitecture,0, + "The architecture of the package file. Unused, empty string nowadays."}, + {"archive",PackageFile_GetArchive,0, + "The archive of the package file (i.e. 'Suite' in the Release file)."}, + {"component",PackageFile_GetComponent,0, + "The component of this package file (e.g. 'main')."}, + {"codename",PackageFile_GetCodename,0, + "The codename of this package file (e.g. squeeze-updates)."}, + {"filename",PackageFile_GetFileName,0, + "The path to the file."}, + {"id",PackageFile_GetID,0, + "The numeric ID of this PackageFile object."}, + {"index_type",PackageFile_GetIndexType,0, + "A string describing the type of index. Known values are\n" + "'Debian Package Index', 'Debian Translation Index', and\n" + "'Debian dpkg status file'."}, + {"label",PackageFile_GetLabel,0, + "The label set in the release file (e.g. 'Debian')."}, + {"not_automatic",PackageFile_GetNotAutomatic,0, + "Whether the NotAutomatic flag is set in the Release file."}, + {"not_source",PackageFile_GetNotSource,0, + "Whether this package file lacks an active (sources.list) source;" + "packages listed in such a file cannot be downloaded."}, + {"origin",PackageFile_GetOrigin,0, + "The origin set in the release file."}, + {"site",PackageFile_GetSite,0, + "The hostname of the location this file comes from."}, + {"size",PackageFile_GetSize,0, + "The size of the file."}, + {"version",PackageFile_GetVersion,0, + "The version set in the release file (e.g. '5.0.X' for lenny, where X\n" + "is a point release)."}, + {} +}; + +static const char *packagefile_doc = + "A package file is an index file stored in the cache with some\n" + "additional pieces of information."; + +PyTypeObject PyPackageFile_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageFile", // tp_name + sizeof(CppPyObject<pkgCache::PkgFileIterator>), // tp_basicsize + 0, // tp_itemsize + CppDealloc<pkgCache::PkgFileIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + PackageFileRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + packagefile_doc, // tp_doc + CppTraverse<pkgCache::PkgFileIterator>, // tp_traverse + CppClear<pkgCache::PkgFileIterator>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + PackageFileGetSet, // tp_getset +}; + +// depends class +static PyObject *DependencyRepr(PyObject *Self) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + + return PyString_FromFormat("<%s object: pkg:'%s' ver:'%s' comp:'%s'>", + Self->ob_type->tp_name, Dep.TargetPkg().Name(), + (Dep.TargetVer() == 0 ? "" : Dep.TargetVer()), + Dep.CompType()); +} + +static PyObject *DepAllTargets(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + + std::unique_ptr<pkgCache::Version *[]> Vers(Dep.AllTargets()); + PyObject *List = PyList_New(0); + for (pkgCache::Version **I = Vers.get(); *I != 0; I++) + { + PyObject *Obj; + Obj = CppPyObject_NEW<pkgCache::VerIterator>(Owner,&PyVersion_Type, + pkgCache::VerIterator(*Dep.Cache(),*I)); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyMethodDef DependencyMethods[] = +{ + {"all_targets",DepAllTargets,METH_VARARGS, + "all_targets() -> list\n\n" + "A list of all possible apt_pkg.Version objects which satisfy this\n" + "dependency."}, + {} +}; + +// Dependency Class /*{{{*/ +// --------------------------------------------------------------------- + +static PyObject *DependencyGetTargetVer(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + if (Dep->Version == 0) + return CppPyString(""); + return CppPyString(Dep.TargetVer()); +} + +static PyObject *DependencyGetTargetPkg(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + return CppPyObject_NEW<pkgCache::PkgIterator>(Owner,&PyPackage_Type, + Dep.TargetPkg()); +} + +static PyObject *DependencyGetParentVer(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + return CppPyObject_NEW<pkgCache::VerIterator>(Owner,&PyVersion_Type, + Dep.ParentVer()); +} + +static PyObject *DependencyGetParentPkg(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + return CppPyObject_NEW<pkgCache::PkgIterator>(Owner,&PyPackage_Type, + Dep.ParentPkg()); +} + +static PyObject *DependencyGetCompType(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return CppPyString(Dep.CompType()); +} + +static PyObject *DependencyGetCompTypeDeb(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return CppPyString(pkgCache::CompTypeDeb(Dep->CompareOp)); +} + +static PyObject *DependencyGetDepType(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return CppPyString(Dep.DepType()); +} + +static PyObject *DependencyGetDepTypeUntranslated(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return CppPyString(UntranslatedDepTypes[Dep->Type]); +} + +static PyObject *DependencyGetDepTypeEnum(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return MkPyNumber(Dep->Type); +} + +static PyObject *DependencyGetID(PyObject *Self,void*) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + return MkPyNumber(Dep->ID); +} + +static PyGetSetDef DependencyGetSet[] = { + {"comp_type",DependencyGetCompType,0, + "The type of comparison in mathematical notation, as a string, namely one " + "of:\n" + "'<', '<=', '=', '!=', '>=', '>', ''.\n" + "The empty string will be returned in case of an unversioned dependency."}, + {"comp_type_deb",DependencyGetCompTypeDeb,0, + "The type of comparison in Debian notation, as a string, namely one of:\n" + "'<<', '<=', '=', '!=', '>=', '>>', ''.\n" + "The empty string will be returned in case of an unversioned dependency.\n" + "For details see the Debian Policy Manual on the syntax of relationship " + "fields:\n" + "https://www.debian.org/doc/debian-policy/ch-relationships.html#s-depsyntax"}, + {"dep_type",DependencyGetDepType,0, + "The type of the dependency; may be translated"}, + {"dep_type_untranslated",DependencyGetDepTypeUntranslated,0, + "Same as dep_type, but guaranteed to be untranslated."}, + {"dep_type_enum",DependencyGetDepTypeEnum,0, + "Same as dep_type, but with a numeric value instead of a string. Can\n" + "be compared against the TYPE_ constants defined in this class."}, + {"id",DependencyGetID,0, + "The numeric ID of this dependency object."}, + {"parent_pkg",DependencyGetParentPkg,0, + "The apt_pkg.Package object of the package which depends."}, + {"parent_ver",DependencyGetParentVer,0, + "The apt_pkg.Version object of the package which depends."}, + {"target_pkg",DependencyGetTargetPkg,0, + "The apt_pkg.Package object of the package depended upon"}, + {"target_ver",DependencyGetTargetVer,0, + "The version of the package depended upon as a string"}, + {} +}; + +static const char *dependency_doc = + "Represent a dependency from one package version to a package,\n" + "and (optionally) a version relation (e.g. >= 1). Dependency\n" + "objects also provide useful functions like all_targets()\n" + "for selecting packages to satisfy the dependency."; + +PyTypeObject PyDependency_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Dependency", // tp_name + sizeof(CppPyObject<pkgCache::DepIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCache::DepIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + DependencyRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + dependency_doc, // tp_doc + CppTraverse<pkgCache::DepIterator>, // tp_traverse + CppClear<pkgCache::DepIterator>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + DependencyMethods, // tp_methods + 0, // tp_members + DependencyGetSet, // tp_getset +}; + + /*}}}*/ + /*}}}*/ +// Reverse Dependency List Class /*{{{*/ +// --------------------------------------------------------------------- +static Py_ssize_t RDepListLen(PyObject *Self) +{ + return GetCpp<RDepListStruct>(Self).Len; +} + +static PyObject *RDepListItem(PyObject *iSelf,Py_ssize_t Index) +{ + RDepListStruct &Self = GetCpp<RDepListStruct>(iSelf); + if (Index < 0 || (unsigned)Index >= Self.Len) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + + if ((unsigned)Index < Self.LastIndex) + { + Self.LastIndex = 0; + Self.Iter = Self.Start; + } + + while ((unsigned)Index > Self.LastIndex) + { + Self.LastIndex++; + Self.Iter++; + if (Self.Iter.end() == true) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + } + + return CppPyObject_NEW<pkgCache::DepIterator>(GetOwner<RDepListStruct>(iSelf), + &PyDependency_Type,Self.Iter); +} + +static PySequenceMethods RDepListSeq = +{ + RDepListLen, + 0, // concat + 0, // repeat + RDepListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +static const char *dependencylist_doc = + "A simple list-like type for representing multiple dependency\n" + "objects in an efficient manner; without having to generate\n" + "all Dependency objects in advance."; +PyTypeObject PyDependencyList_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.DependencyList", // tp_name + sizeof(CppPyObject<RDepListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<RDepListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &RDepListSeq, // 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 | Py_TPFLAGS_HAVE_GC, // tp_flags + dependencylist_doc, // tp_doc + CppTraverse<RDepListStruct>, // tp_traverse + CppClear<RDepListStruct>, // tp_clear +}; + + /*}}}*/ + + diff --git a/python/cachegroup.cc b/python/cachegroup.cc new file mode 100644 index 0000000..4fc6c37 --- /dev/null +++ b/python/cachegroup.cc @@ -0,0 +1,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 +}; diff --git a/python/cdrom.cc b/python/cdrom.cc new file mode 100644 index 0000000..392dd83 --- /dev/null +++ b/python/cdrom.cc @@ -0,0 +1,139 @@ +/* cdrom.cc - Wrapper for pkgCdrom. + * + * Copyright 2004-2009 Canonical Ltd. + * Copyright 2009 Julian Andres Klode <jak@debian.org> + * + * Authors: Michael Vogt + * Julian Andres Klode + * + * 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 "generic.h" +#include "apt_pkgmodule.h" +#include "progress.h" + +#include <apt-pkg/cdrom.h> + +static char *cdrom_add_doc = + "add(progress: apt_pkg.CdromProgress) -> bool\n\n" + "Add the given CD-ROM to the sources.list. Return True on success;\n" + "raise an error on failure or return False."; +static PyObject *cdrom_add(PyObject *Self,PyObject *Args) +{ + pkgCdrom &Cdrom = GetCpp<pkgCdrom>(Self); + + PyObject *pyCdromProgressInst = 0; + if (PyArg_ParseTuple(Args, "O", &pyCdromProgressInst) == 0) { + return 0; + } + + PyCdromProgress progress; + progress.setCallbackInst(pyCdromProgressInst); + + bool res = Cdrom.Add(&progress); + + return HandleErrors(PyBool_FromLong(res)); +} + +static char *cdrom_ident_doc = + "ident(progress: apt_pkg.CdromProgress) -> str\n\n" + "Try to identify the CD-ROM and if successful return the hexadecimal\n" + "CDROM-ID (and a integer version suffix separated by -) as a\n" + "string. Otherwise, return None or raise an error.\n\n" + "The ID is created by hashing all file and directory names on the\n" + "CD-ROM and appending the version."; +static PyObject *cdrom_ident(PyObject *Self,PyObject *Args) +{ + pkgCdrom &Cdrom = GetCpp<pkgCdrom>(Self); + PyObject *pyCdromProgressInst = 0; + if (PyArg_ParseTuple(Args, "O", &pyCdromProgressInst) == 0) { + return 0; + } + + PyCdromProgress progress; + progress.setCallbackInst(pyCdromProgressInst); + + std::string ident; + bool res = Cdrom.Ident(ident, &progress); + + if (res) + return CppPyString(ident); + else { + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } +} + + +static PyMethodDef cdrom_methods[] = { + {"add",cdrom_add,METH_VARARGS,cdrom_add_doc}, + {"ident",cdrom_ident,METH_VARARGS,cdrom_ident_doc}, + {} +}; + +static PyObject *cdrom_new(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + return CppPyObject_NEW<pkgCdrom>(NULL, type); +} + +static char *cdrom_doc = + "Cdrom()\n\n" + "Cdrom objects can be used to identify Debian installation media and to\n" + "add them to /etc/apt/sources.list."; +PyTypeObject PyCdrom_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Cdrom", // tp_name + sizeof(CppPyObject<pkgCdrom>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCdrom>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE, + cdrom_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + cdrom_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 + cdrom_new, // tp_new +}; + diff --git a/python/configuration.cc b/python/configuration.cc new file mode 100644 index 0000000..dab2cc4 --- /dev/null +++ b/python/configuration.cc @@ -0,0 +1,613 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: configuration.cc,v 1.4 2003/06/03 03:22:27 mdz Exp $ +/* ###################################################################### + + Configuration - Binding for the configuration object. + + The Configuration object can have an owner (a parent Configuration object), + and it always uses a pointer. + + The wrapping is mostly 1:1 with the C++ code, but there are additions to + wrap the linked tree walking into nice flat sequence walking. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/configuration.h> +#include <apt-pkg/cmndline.h> +#include <sstream> +#include <Python.h> + /*}}}*/ + +// GetSelf - Convert PyObject to Configuration /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static inline Configuration &GetSelf(PyObject *Obj) +{ + return *GetCpp<Configuration*>(Obj); +} + /*}}}*/ + +// Method Wrappers /*{{{*/ +static const char *doc_Find = + "find(key: str[, default: str = '']) -> str\n\n" + "Find the value for the given key and return it. If the\n" + "given key does not exist, return default instead."; +static PyObject *CnfFind(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyString(GetSelf(Self).Find(Name,Default)); +} + +static const char *doc_FindFile = + "find_file(key: str[, default: str = '']) -> str\n\n" + "Same as find(), but for filenames. In the APT configuration, there\n" + "is a special section Dir:: for storing filenames. find_file() locates\n" + "the given key and then goes up and prepends the directory names to the\n" + "return value. For example, for:\n" + "\n" + " apt_pkg.config['Dir'] = 'a'\n" + " apt_pkg.config['Dir::D'] = 'b'\n" + " apt_pkg.config['Dir::D::F'] = 'c'\n" + "\n" + "find_file('Dir::D::F') returns 'a/b/c'. There is also a special\n" + "configuration setting RootDir which will always be prepended to the\n" + "result (the default being ''). Thus, if RootDir is 'x', the example\n" + "would return 'x/a/b/c'."; +static PyObject *CnfFindFile(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyPath(GetSelf(Self).FindFile(Name,Default)); +} + +static const char *doc_FindDir = + "find_dir(key: str[, default: str = '']) -> str\n\n" + "Same as find_file(), but for directories. The difference is\n" + "that this function adds a trailing slash to the result."; +static PyObject *CnfFindDir(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyPath(GetSelf(Self).FindDir(Name,Default)); +} + +static const char *doc_FindI = + "find_i(key: str[, default: int = 0]) -> int\n\n" + "Same as find, but for integer values."; +static PyObject *CnfFindI(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + int Default = 0; + if (PyArg_ParseTuple(Args,"s|i",&Name,&Default) == 0) + return 0; + return MkPyNumber(GetSelf(Self).FindI(Name,Default)); +} + +static const char *doc_FindB = + "find_i(key: str[, default: bool = False]) -> bool\n\n" + "Same as find, but for boolean values; returns False on unknown values."; +static PyObject *CnfFindB(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + int Default = 0; + if (PyArg_ParseTuple(Args,"s|i",&Name,&Default) == 0) + return 0; + return PyBool_FromLong(GetSelf(Self).FindB(Name,(Default == 0?false:true))); +} + +static const char *doc_Set = + "set(key: str, value: str)\n\n" + "Set the given key to the given value. To set int or bool values,\n" + "encode them using str(value) and then use find_i()/find_b()\n" + "to retrieve their value again."; +static PyObject *CnfSet(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Value = 0; + if (PyArg_ParseTuple(Args,"ss",&Name,&Value) == 0) + return 0; + + GetSelf(Self).Set(Name,Value); + Py_INCREF(Py_None); + return Py_None; +} + +static const char *doc_Exists = + "exists(key: str) -> bool\n\n" + "Check whether the given key exists."; +static PyObject *CnfExists(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + return PyBool_FromLong((int)GetSelf(Self).Exists(Name)); +} + +static int CnfContains(PyObject *Self,PyObject *Arg) +{ + return (int)GetSelf(Self).Exists(PyString_AsString(Arg)); +} + +static const char *doc_Clear = + "clear(key: str)\n\n" + "Remove the specified option and all sub-options."; +static PyObject *CnfClear(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + GetSelf(Self).Clear(Name); + + Py_INCREF(Py_None); + return Py_None; +} + +// The amazing narrowing search ability! +static const char *doc_SubTree = + "subtree(key: str) -> apt_pkg.Configuration\n\n" + + "Return a new apt_pkg.Configuration object with the given option\n" + "as its root. Example:\n\n" + " apttree = config.subtree('APT')\n" + " apttree['Install-Suggests'] = config['APT::Install-Suggests']"; +static PyObject *CnfSubTree(PyObject *Self,PyObject *Args) +{ + char *Name; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + const Configuration::Item *Itm = GetSelf(Self).Tree(Name); + if (Itm == 0) + { + PyErr_SetString(PyExc_KeyError,Name); + return 0; + } + + return CppPyObject_NEW<Configuration*>(Self,&PyConfiguration_Type, + new Configuration(Itm)); +} + +// Return a list of items at a specific level +static char *doc_List = + "list([root: str]) -> list\n\n" + "Return a list of all items at the given root, using their full\n" + "name. For example, in a configuration object where the options A,\n" + "B, and B::C are set, the following expressions evaluate to True:\n\n" + " conf.list() == ['A', 'B']\n" + " conf.list('A') == ['']\n" + " conf.list('B') == ['B::C']\n"; +static PyObject *CnfList(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + if (!GetSelf(Self).Tree(0)) + return List; + const Configuration::Item *Root = GetSelf(Self).Tree(0)->Parent; + if (Top != 0 && RootName != 0) + Top = Top->Child; + for (; Top != 0; Top = Top->Next) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->FullTag(Root))); + Py_DECREF(Obj); + } + + return List; +} + +/* Return a list of values of items at a specific level.. This is used to + get out value lists */ +static char *doc_ValueList = + "value_list([root: str]) -> list\n\n" + "Same as list(), but instead of returning the keys, return the values."; +static PyObject *CnfValueList(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + if (Top != 0 && RootName != 0) + Top = Top->Child; + for (; Top != 0; Top = Top->Next) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->Value)); + Py_DECREF(Obj); + } + + return List; +} + +static char *doc_MyTag = + "my_tag() -> str\n\n" + "Return the tag of the root of this Configuration object. For the\n" + "default object, this is an empty string. For a subtree('APT') of\n" + "such an object, it would be 'APT' (given as an example)."; +static PyObject *CnfMyTag(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + const Configuration::Item *Top = GetSelf(Self).Tree(0); + if (Top == 0) + return Py_BuildValue("s",""); + return CppPyString(Top->Parent->Tag); +} + +static char *doc_Dump = + "dump() -> str\n\n" + "Return a string dump this Configuration object."; +static PyObject *CnfDump(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + std::stringstream ss; + GetSelf(Self).Dump(ss); + return CppPyString(ss.str()); +} + + +// Look like a mapping +static char *doc_Keys = + "keys([root: str]) -> list\n\n" + "Return a list of all keys in the configuration object. If 'root'\n" + "is given, limit the list to those below the root."; +static PyObject *CnfKeys(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + const Configuration::Item *Stop = Top; + const Configuration::Item *Root = 0; + if (RootName == 0) + Stop = 0; + if (Top != 0 && GetSelf(Self).Tree(0)) + Root = GetSelf(Self).Tree(0)->Parent; + for (; Top != 0;) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->FullTag(Root))); + Py_DECREF(Obj); + + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0 && Top != Root && + Top->Parent != Stop) + Top = Top->Parent; + if (Top != 0) + Top = Top->Next; + } + + return List; +} + +// Map access, operator [] +static PyObject *CnfMap(PyObject *Self,PyObject *Arg) +{ + if (PyString_Check(Arg) == 0) + { + PyErr_SetNone(PyExc_TypeError); + return 0; + } + + if (GetSelf(Self).Exists(PyString_AsString(Arg)) == false) + { + PyErr_SetString(PyExc_KeyError,PyString_AsString(Arg)); + return 0; + } + + return CppPyString(GetSelf(Self).Find(PyString_AsString(Arg))); +} + +// Assignment with operator [] +static int CnfMapSet(PyObject *Self,PyObject *Arg,PyObject *Val) +{ + if (PyString_Check(Arg) == 0 || (Val != NULL && PyString_Check(Val) == 0)) + { + PyErr_SetNone(PyExc_TypeError); + return -1; + } + + if (Val == NULL) + GetSelf(Self).Clear(PyString_AsString(Arg)); + else + GetSelf(Self).Set(PyString_AsString(Arg),PyString_AsString(Val)); + return 0; +} + /*}}}*/ +// Config file loaders /*{{{*/ +char *doc_LoadConfig = + "read_config_file(configuration: apt_pkg.Configuration, filename: str)\n\n" + "Read the configuration file 'filename' and set the appropriate\n" + "options in the configuration object."; +PyObject *LoadConfig(PyObject *Self,PyObject *Args) +{ + PyApt_Filename Name; + if (PyArg_ParseTuple(Args,"OO&",&Self,PyApt_Filename::Converter, &Name) == 0) + return 0; + if (PyConfiguration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (ReadConfigFile(GetSelf(Self),Name,false) == false) + return HandleErrors(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} +char *doc_LoadConfigISC = + "read_config_file_isc(configuration: apt_pkg.Configuration, filename: str)\n\n" + "Like read_config_file(), but for configuration files like bind's\n" + "named.conf. They have a slightly different format than APT\n" + "configuration files."; +PyObject *LoadConfigISC(PyObject *Self,PyObject *Args) +{ + PyApt_Filename Name; + if (PyArg_ParseTuple(Args,"OO&",&Self,PyApt_Filename::Converter, &Name) == 0) + return 0; + if (PyConfiguration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (ReadConfigFile(GetSelf(Self),Name,true) == false) + return HandleErrors(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} +char *doc_LoadConfigDir = + "read_config_dir(configuration: apt_pkg.Configuration, dirname: str)\n\n" + "Read all configuration files in the dir given by 'dirname' in the\n" + "correct order."; +PyObject *LoadConfigDir(PyObject *Self,PyObject *Args) +{ + PyApt_Filename Name; + if (PyArg_ParseTuple(Args,"OO&",&Self,PyApt_Filename::Converter, &Name) == 0) + return 0; + if (PyConfiguration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (ReadConfigDir(GetSelf(Self),Name,false) == false) + return HandleErrors(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + /*}}}*/ + +// ParseCommandLine - Wrapper for the command line interface /*{{{*/ +// --------------------------------------------------------------------- +char *doc_ParseCommandLine = +"parse_commandLine(config: Configuration, options: list, argv: list) -> list\n" +"\n" +"Parse the command line in 'argv' into the configuration space. The\n" +"list 'options' contains a list of 3-tuples or 4-tuples in the form:\n" +"\n" +" (short_option: str, long_option: str, variable: str[, type: str])\n" +"\n" +"The element 'short_option' is one character, the 'long_option' element\n" +"is the name of the long option, the element 'variable' the name of the\n" +"configuration option the result will be stored in and type is one of\n" +"'HasArg', 'IntLevel', 'Boolean', 'InvBoolean', 'ConfigFile',\n" +"'ArbItem'. The default type is 'Boolean'. Read the online documentation\n" +"in python-apt-doc and its tutorial on writing an apt-cdrom clone for more\n" +"details."; +PyObject *ParseCommandLine(PyObject *Self,PyObject *Args) +{ + PyObject *POList; + PyObject *Pargv; + if (PyArg_ParseTuple(Args,"OO!O!",&Self, + &PyList_Type,&POList,&PyList_Type,&Pargv) == 0) + return 0; + if (PyConfiguration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (PySequence_Length(Pargv) < 1) { + PyErr_SetString(PyExc_ValueError,"argv is an empty sequence"); + return 0; + } + // Convert the option list + int Length = PySequence_Length(POList); + CommandLine::Args *OList = new CommandLine::Args[Length+1]; + OList[Length].ShortOpt = 0; + OList[Length].LongOpt = 0; + + for (int I = 0; I != Length; I++) + { + char *Type = 0; + #if PY_MAJOR_VERSION >= 3 + if (PyArg_ParseTuple(PySequence_GetItem(POList,I),"Czs|s", + #else + if (PyArg_ParseTuple(PySequence_GetItem(POList,I),"czs|s", + #endif + &OList[I].ShortOpt,&OList[I].LongOpt, + &OList[I].ConfName,&Type) == 0) + { + delete [] OList; + return 0; + } + OList[I].Flags = 0; + + // Convert the type over to flags.. + if (Type != 0) + { + if (strcasecmp(Type,"HasArg") == 0) + OList[I].Flags = CommandLine::HasArg; + else if (strcasecmp(Type,"IntLevel") == 0) + OList[I].Flags = CommandLine::IntLevel; + else if (strcasecmp(Type,"Boolean") == 0) + OList[I].Flags = CommandLine::Boolean; + else if (strcasecmp(Type,"InvBoolean") == 0) + OList[I].Flags = CommandLine::InvBoolean; + else if (strcasecmp(Type,"ConfigFile") == 0) + OList[I].Flags = CommandLine::ConfigFile; + else if (strcasecmp(Type,"ArbItem") == 0) + OList[I].Flags = CommandLine::ArbItem; + } + } + + // Convert the argument list into a char ** + const char **argv = ListToCharChar(Pargv); + if (argv == 0) + { + delete [] OList; + return 0; + } + + // Do the command line processing + PyObject *List = 0; + { + CommandLine CmdL(OList,&GetSelf(Self)); + if (CmdL.Parse(PySequence_Length(Pargv),argv) == false) + { + delete [] argv; + delete [] OList; + return HandleErrors(); + } + + // Convert the file listing into a python sequence + for (Length = 0; CmdL.FileList[Length] != 0; Length++); + List = PyList_New(Length); + for (int I = 0; CmdL.FileList[I] != 0; I++) + { + PyList_SetItem(List,I,CppPyString(CmdL.FileList[I])); + } + } + + delete [] argv; + delete [] OList; + return HandleErrors(List); +} + /*}}}*/ + +// Method table for the Configuration object +static PyMethodDef CnfMethods[] = +{ + // Query + {"find",CnfFind,METH_VARARGS,doc_Find}, + {"find_file",CnfFindFile,METH_VARARGS,doc_FindFile}, + {"find_dir",CnfFindDir,METH_VARARGS,doc_FindDir}, + {"find_i",CnfFindI,METH_VARARGS,doc_FindI}, + {"find_b",CnfFindB,METH_VARARGS,doc_FindB}, + + // Others + {"set",CnfSet,METH_VARARGS,doc_Set}, + {"exists",CnfExists,METH_VARARGS,doc_Exists}, + {"subtree",CnfSubTree,METH_VARARGS,doc_SubTree}, + {"list",CnfList,METH_VARARGS,doc_List}, + {"value_list",CnfValueList,METH_VARARGS,doc_ValueList}, + {"my_tag",CnfMyTag,METH_VARARGS,doc_MyTag}, + {"clear",CnfClear,METH_VARARGS,doc_Clear}, + {"dump",CnfDump,METH_VARARGS,doc_Dump}, + // Python Special + {"keys",CnfKeys,METH_VARARGS,doc_Keys}, + #if PY_MAJOR_VERSION < 3 + {"has_key",CnfExists,METH_VARARGS,doc_Exists}, + #endif + {"get",CnfFind,METH_VARARGS,doc_Find}, + {} +}; + +static PyObject *CnfNew(PyTypeObject *type, PyObject *args, PyObject *kwds) { + char *kwlist[] = {NULL}; + if (PyArg_ParseTupleAndKeywords(args,kwds,"",kwlist) == 0) + return 0; + return CppPyObject_NEW<Configuration*>(NULL, type, new Configuration()); +} + +// Type for a Normal Configuration object +static PySequenceMethods ConfigurationSeq = {0,0,0,0,0,0,0,CnfContains,0,0}; +static PyMappingMethods ConfigurationMap = {0,CnfMap,CnfMapSet}; + +static const char *configuration_doc = + "Configuration()\n\n" + "Represent the configuration of APT by mapping option keys to\n" + "values and storing configuration parsed from files like\n" + "/etc/apt/apt.conf. The most important Configuration object\n" + "is apt_pkg.config which points to the global configuration\n" + "object. Other top-level Configuration objects can be created\n" + "by calling the constructor, but there is usually no reason to."; + +PyTypeObject PyConfiguration_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Configuration", // tp_name + sizeof(CppPyObject<Configuration*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<Configuration*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &ConfigurationSeq, // tp_as_sequence + &ConfigurationMap, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + configuration_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + CnfMethods, // 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 + CnfNew, // tp_new +}; + diff --git a/python/depcache.cc b/python/depcache.cc new file mode 100644 index 0000000..ed766c4 --- /dev/null +++ b/python/depcache.cc @@ -0,0 +1,1169 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: depcache.cc,v 1.5 2003/06/03 03:03:23 mdz Exp $ +/* ###################################################################### + + DepCache - Wrapper for the depcache related functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/policy.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/upgrade.h> +#include <Python.h> + +#include <iostream> +#include "progress.h" + +#ifndef _ +#define _(x) (x) +#endif + + +#define VALIDATE_ITERATOR(I) do { \ + if ((I).Cache() != &depcache->GetCache()) { \ + PyErr_SetString(PyAptCacheMismatchError, "Object of different cache passed as argument to apt_pkg.DepCache method"); \ + return nullptr; \ + } \ +} while(0) + + +// DepCache Class /*{{{*/ +// --------------------------------------------------------------------- + + + +static PyObject *PkgDepCacheInit(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *pyCallbackInst = 0; + if (PyArg_ParseTuple(Args, "|O", &pyCallbackInst) == 0) + return 0; + + if(pyCallbackInst != 0) { + PyOpProgress progress; + progress.setCallbackInst(pyCallbackInst); + depcache->Init(&progress); + } else { + depcache->Init(0); + } + + pkgApplyStatus(*depcache); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgDepCacheCommit(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *pyInstallProgressInst = 0; + PyObject *pyFetchProgressInst = 0; + if (PyArg_ParseTuple(Args, "OO", + &pyFetchProgressInst, &pyInstallProgressInst) == 0) { + return 0; + } + + pkgAcquire Fetcher; + if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false) { + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } + + pkgRecords Recs(*depcache); + if (_error->PendingError() == true) + HandleErrors(Py_None); + + pkgSourceList List; + if(!List.ReadMainList()) + return HandleErrors(Py_None); + + PyFetchProgress progress; + progress.setCallbackInst(pyFetchProgressInst); + + pkgPackageManager *PM; + PM = _system->CreatePM(depcache); + + Fetcher.SetLog(&progress); + + if(PM->GetArchives(&Fetcher, &List, &Recs) == false || + _error->PendingError() == true) { + std::cerr << "Error in GetArchives" << std::endl; + return HandleErrors(); + } + + PyInstallProgress iprogress; + iprogress.setCallbackInst(pyInstallProgressInst); + + // Run it + while (1) + { + bool Transient = false; + + if (Fetcher.Run() == pkgAcquire::Failed) + return HandleErrors(); + + // Print out errors + bool Failed = false; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + { + + if ((*I)->Status == pkgAcquire::Item::StatDone && + (*I)->Complete == true) + continue; + + if ((*I)->Status == pkgAcquire::Item::StatIdle) + { + Transient = true; + //Failed = true; + continue; + } + + _error->Warning(_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), + (*I)->ErrorText.c_str()); + Failed = true; + } + + if (Transient == true && Failed == true) + { + _error->Error(_("--fix-missing and media swapping is not currently supported")); + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } + + // Try to deal with missing package files + if (Failed == true && PM->FixMissing() == false) + { + _error->Error("Aborting install."); + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } + + // fail if something else went wrong + //FIXME: make this more flexible, e.g. with a failedDl handler + if(Failed) + Py_RETURN_FALSE; + _system->UnLockInner(true); + + pkgPackageManager::OrderResult Res = iprogress.Run(PM); + + if (Res == pkgPackageManager::Failed || _error->PendingError() == true) { + return HandleErrors(PyBool_FromLong(false)); + } + if (Res == pkgPackageManager::Completed) { + Py_RETURN_TRUE; + } + + // Reload the fetcher object and loop again for media swapping + Fetcher.Shutdown(); + if (PM->GetArchives(&Fetcher,&List,&Recs) == false) { + Py_RETURN_FALSE; + } + _system->LockInner(); + } + + return HandleErrors(Py_None); +} + +static PyObject *PkgDepCacheSetCandidateRelease(PyObject *Self,PyObject *Args) +{ + bool Success; + PyObject *PackageObj; + PyObject *VersionObj; + const char *target_rel; + std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > Changed; + if (PyArg_ParseTuple(Args,"O!O!s", + &PyPackage_Type, &PackageObj, + &PyVersion_Type, &VersionObj, + &target_rel) == 0) + return 0; + + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + pkgCache::VerIterator &I = GetCpp<pkgCache::VerIterator>(VersionObj); + if(I.end()) { + return HandleErrors(PyBool_FromLong(false)); + } + VALIDATE_ITERATOR(I); + + Success = depcache->SetCandidateRelease(I, target_rel, Changed); + + return HandleErrors(PyBool_FromLong(Success)); +} + +static PyObject *PkgDepCacheSetCandidateVer(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + PyObject *PackageObj; + PyObject *VersionObj; + if (PyArg_ParseTuple(Args,"O!O!", + &PyPackage_Type, &PackageObj, + &PyVersion_Type, &VersionObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + + VALIDATE_ITERATOR(Pkg); + + pkgCache::VerIterator &I = GetCpp<pkgCache::VerIterator>(VersionObj); + if(I.end()) { + return HandleErrors(PyBool_FromLong(false)); + } + VALIDATE_ITERATOR(I); + + if (I.ParentPkg() != Pkg) { + PyErr_SetString(PyExc_ValueError, "Version does not belong to package"); + return nullptr; + } + + depcache->SetCandidateVersion(I); + + return HandleErrors(PyBool_FromLong(true)); +} + +static PyObject *PkgDepCacheGetCandidateVer(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + PyObject *PackageObj; + PyObject *CandidateObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + + VALIDATE_ITERATOR(Pkg); + + pkgDepCache::StateCache & State = (*depcache)[Pkg]; + pkgCache::VerIterator I = State.CandidateVerIter(*depcache); + + if(I.end()) { + Py_INCREF(Py_None); + return Py_None; + } + CandidateObj = CppPyObject_NEW<pkgCache::VerIterator>(PackageObj,&PyVersion_Type,I); + + return CandidateObj; +} + +static PyObject *PkgDepCacheUpgrade(PyObject *Self,PyObject *Args) +{ + bool res; + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + char distUpgrade=0; + if (PyArg_ParseTuple(Args,"|b",&distUpgrade) == 0) + return 0; + + Py_BEGIN_ALLOW_THREADS + if(distUpgrade) + res = APT::Upgrade::Upgrade(*depcache, 0); + else + res = APT::Upgrade::Upgrade(*depcache, APT::Upgrade::FORBID_REMOVE_PACKAGES | + APT::Upgrade::FORBID_INSTALL_NEW_PACKAGES); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + +static PyObject *PkgDepCacheMinimizeUpgrade(PyObject *Self,PyObject *Args) +{ + bool res; + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Py_BEGIN_ALLOW_THREADS + res = pkgMinimizeUpgrade(*depcache); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return HandleErrors(PyBool_FromLong(res)); +} + + +static PyObject *PkgDepCacheReadPinFile(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + + char *file=NULL; + if (PyArg_ParseTuple(Args,"|s",&file) == 0) + return 0; + + if(file == NULL) + ReadPinFile((pkgPolicy&)depcache->GetPolicy()); + else + ReadPinFile((pkgPolicy&)depcache->GetPolicy(), file); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + + +static PyObject *PkgDepCacheFixBroken(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + bool res=true; + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + res &=pkgFixBroken(*depcache); + res &=pkgMinimizeUpgrade(*depcache); + + return HandleErrors(PyBool_FromLong(res)); +} + + +static PyObject *PkgDepCacheMarkKeep(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache*>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + depcache->MarkKeep(Pkg); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgDepCacheSetReInstall(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache*>(Self); + + PyObject *PackageObj; + char value = 0; + if (PyArg_ParseTuple(Args,"O!b",&PyPackage_Type,&PackageObj, &value) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + depcache->SetReInstall(Pkg,value); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + + +static PyObject *PkgDepCacheMarkDelete(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + char purge = 0; + if (PyArg_ParseTuple(Args,"O!|b",&PyPackage_Type,&PackageObj, &purge) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + depcache->MarkDelete(Pkg,purge); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + + +static PyObject *PkgDepCacheMarkInstall(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + char autoInst=1; + char fromUser=1; + if (PyArg_ParseTuple(Args,"O!|bb",&PyPackage_Type,&PackageObj, + &autoInst, &fromUser) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + + Py_BEGIN_ALLOW_THREADS + depcache->MarkInstall(Pkg, autoInst, 0, fromUser); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgDepCacheMarkAuto(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache*>(Self); + + PyObject *PackageObj; + char value = 0; + if (PyArg_ParseTuple(Args,"O!b",&PyPackage_Type,&PackageObj, &value) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + depcache->MarkAuto(Pkg,value); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgDepCacheIsUpgradable(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Upgradable())); +} + +static PyObject *PkgDepCacheIsGarbage(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Garbage)); +} + +static PyObject *PkgDepCacheIsAutoInstalled(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Flags & pkgCache::Flag::Auto)); +} + +static PyObject *PkgDepCacheIsNowBroken(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.NowBroken())); +} + +static PyObject *PkgDepCacheIsInstBroken(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.InstBroken())); +} + + +static PyObject *PkgDepCacheMarkedInstall(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.NewInstall())); +} + + +static PyObject *PkgDepCacheMarkedUpgrade(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Upgrade())); +} + +static PyObject *PkgDepCacheMarkedDelete(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Delete())); +} + +static PyObject *PkgDepCacheMarkedKeep(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Keep())); +} + +static PyObject *PkgDepCacheMarkedDowngrade(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(PyBool_FromLong(state.Downgrade())); +} + +static PyObject *PkgDepCacheMarkedReinstall(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + bool res = state.Install() && (state.iFlags & pkgDepCache::ReInstall); + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyObject *PkgDepCachePhasingApplied(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + bool res=false; + PyObject *PackageObj; + + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + res = depcache->PhasingApplied(Pkg); + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyMethodDef PkgDepCacheMethods[] = +{ + {"init",PkgDepCacheInit,METH_VARARGS, + "init(progress: apt.progress.base.OpProgress)\n\n" + "Initialize the depcache (done automatically when constructing\n" + "the object)."}, + {"get_candidate_ver",PkgDepCacheGetCandidateVer,METH_VARARGS, + "get_candidate_ver(pkg: apt_pkg.Package) -> apt_pkg.Version\n\n" + "Return the candidate version for the package, normally the version\n" + "with the highest pin (changeable using set_candidate_ver)."}, + {"set_candidate_ver",PkgDepCacheSetCandidateVer,METH_VARARGS, + "set_candidate_ver(pkg: apt_pkg.Package, ver: apt_pkg.Version) -> bool\n\n" + "Set the candidate version of 'pkg' to 'ver'."}, + {"set_candidate_release",PkgDepCacheSetCandidateRelease,METH_VARARGS, + "set_candidate_release(pkg: apt_pkg.Package, ver: apt_pkg.Version, rel: string) -> bool\n\n" + "Sets not only the candidate version 'ver' for package 'pkg', " + "but walks also down the dependency tree and checks if it is required " + "to set the candidate of the dependency to a version from the given " + "release string 'rel', too."}, + + // global cache operations + {"upgrade",PkgDepCacheUpgrade,METH_VARARGS, + "upgrade([dist_upgrade: bool = True]) -> bool\n\n" + "Mark the packages for upgrade under the same conditions apt-get\n" + "upgrade does. If 'dist_upgrade' is True, also allow packages to\n" + "be upgraded if they require installation/removal of other packages;\n" + "just like apt-get dist-upgrade."}, + {"fix_broken",PkgDepCacheFixBroken,METH_VARARGS, + "fix_broken() -> bool\n\n" + "Fix broken packages."}, + {"read_pinfile",PkgDepCacheReadPinFile,METH_VARARGS, + "read_pinfile([file: str])\n\n" + "Read the pin policy"}, + {"minimize_upgrade",PkgDepCacheMinimizeUpgrade, METH_VARARGS, + "minimize_upgrade() -> bool\n\n" + "Go over the entire set of packages and try to keep each package\n" + "marked for upgrade. If a conflict is generated then the package\n" + "is restored."}, + // Policy + {"phasing_applied",PkgDepCachePhasingApplied,METH_VARARGS, + "phasing_applied(pkg: apt_pkg.Package) -> bool\n\n" + "Check if the phased update is ready.\n" + "return false if this is a phased update that is not yet ready for us.\n"}, + // Manipulators + {"mark_keep",PkgDepCacheMarkKeep,METH_VARARGS, + "mark_keep(pkg: apt_pkg.Package)\n\n" + "Mark package to be kept."}, + {"mark_delete",PkgDepCacheMarkDelete,METH_VARARGS, + "mark_delete(pkg: apt_pkg.Package[, purge: bool = False])\n\n" + "Mark package for deletion, and if 'purge' is True also for purging."}, + {"mark_install",PkgDepCacheMarkInstall,METH_VARARGS, + "mark_install(pkg: apt_pkg.Package[, auto_inst=True, from_user=True])\n\n" + "Mark the package for installation. The parameter 'auto_inst' controls\n" + "whether the dependencies of the package are marked for installation\n" + "as well. The parameter 'from_user' controls whether the package is\n" + "registered as NOT automatically installed."}, + {"mark_auto",PkgDepCacheMarkAuto,METH_VARARGS, + "mark_auto(pkg: apt_pkg.Package, auto: bool)\n\n" + "Mark package as automatically installed (if auto=True),\n" + "or as not automatically installed (if auto=False)."}, + {"set_reinstall",PkgDepCacheSetReInstall,METH_VARARGS, + "set_reinstall(pkg: apt_pkg.Package, reinstall: bool)\n\n" + "Set whether the package should be reinstalled (reinstall = True or False)."}, + // state information + {"is_upgradable",PkgDepCacheIsUpgradable,METH_VARARGS, + "is_upgradable(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is upgradable."}, + {"is_now_broken",PkgDepCacheIsNowBroken,METH_VARARGS, + "is_now_broken(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is broken, taking marked changes into account."}, + {"is_inst_broken",PkgDepCacheIsInstBroken,METH_VARARGS, + "is_inst_broken(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is broken, ignoring marked changes."}, + {"is_garbage",PkgDepCacheIsGarbage,METH_VARARGS, + "is_garbage(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is garbage, i.e. whether it is automatically\n" + "installed and the reverse dependencies are not installed anymore."}, + {"is_auto_installed",PkgDepCacheIsAutoInstalled,METH_VARARGS, + "is_auto_installed(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked as automatically installed."}, + {"marked_install",PkgDepCacheMarkedInstall,METH_VARARGS, + "marked_install(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked for installation."}, + {"marked_upgrade",PkgDepCacheMarkedUpgrade,METH_VARARGS, + "marked_upgrade(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked for upgrade."}, + {"marked_delete",PkgDepCacheMarkedDelete,METH_VARARGS, + "marked_delete(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked for removal."}, + {"marked_keep",PkgDepCacheMarkedKeep,METH_VARARGS, + "marked_keep(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package should be kept."}, + {"marked_reinstall",PkgDepCacheMarkedReinstall,METH_VARARGS, + "marked_reinstall(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked for re-installation."}, + {"marked_downgrade",PkgDepCacheMarkedDowngrade,METH_VARARGS, + "marked_downgrade(pkg: apt_pkg.Package) -> bool\n\n" + "Check whether the package is marked for downgrade."}, + // Action + {"commit", PkgDepCacheCommit, METH_VARARGS, + "commit(acquire_progress, install_progress)\n\n" + "Commit all the marked changes. This method takes two arguments,\n" + "'acquire_progress' takes an apt.progress.base.AcquireProgress\n" + "object and 'install_progress' an apt.progress.base.InstallProgress\n" + "object."}, + {} +}; + +#define depcache (GetCpp<pkgDepCache *>(Self)) +static PyObject *PkgDepCacheGetKeepCount(PyObject *Self,void*) { + return MkPyNumber(depcache->KeepCount()); +} +static PyObject *PkgDepCacheGetInstCount(PyObject *Self,void*) { + return MkPyNumber(depcache->InstCount()); +} +static PyObject *PkgDepCacheGetDelCount(PyObject *Self,void*) { + return MkPyNumber(depcache->DelCount()); +} +static PyObject *PkgDepCacheGetBrokenCount(PyObject *Self,void*) { + return MkPyNumber(depcache->BrokenCount()); +} +static PyObject *PkgDepCacheGetUsrSize(PyObject *Self,void*) { + return MkPyNumber(depcache->UsrSize()); +} +static PyObject *PkgDepCacheGetDebSize(PyObject *Self,void*) { + return MkPyNumber(depcache->DebSize()); +} +#undef depcache + +static PyObject *PkgDepCacheGetPolicy(PyObject *Self,void*) { + PyObject *Owner = GetOwner<pkgDepCache*>(Self); + pkgDepCache *DepCache = GetCpp<pkgDepCache*>(Self); + pkgPolicy *Policy = (pkgPolicy *)&DepCache->GetPolicy(); + CppPyObject<pkgPolicy*> *PyPolicy = + CppPyObject_NEW<pkgPolicy*>(Owner,&PyPolicy_Type,Policy); + // Policy should not be deleted, it is managed by CacheFile. + PyPolicy->NoDelete = true; + return PyPolicy; +} + + +static PyGetSetDef PkgDepCacheGetSet[] = { + {"broken_count",PkgDepCacheGetBrokenCount,0, + "The number of packages with broken dependencies in the cache."}, + {"deb_size",PkgDepCacheGetDebSize,0, + "The size of the packages which are needed for the changes to be\n" + "applied."}, + {"del_count",PkgDepCacheGetDelCount,0, + "The number of packages marked for removal."}, + {"inst_count",PkgDepCacheGetInstCount,0, + "The number of packages marked for installation."}, + {"keep_count",PkgDepCacheGetKeepCount,0, + "The number of packages marked for keep."}, + {"usr_size",PkgDepCacheGetUsrSize,0, + "The amount of space required for installing/removing the packages,\n" + "i.e. the Installed-Size of all packages marked for installation\n" + "minus the Installed-Size of all packages for removal."}, + {"policy",PkgDepCacheGetPolicy,0, + "The apt_pkg.Policy object used by this cache."}, + {} +}; + +static PyObject *PkgDepCacheNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"cache", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyCache_Type, + &Owner) == 0) + return 0; + + + // the owner of the Python cache object is a cachefile object, get it + PyObject *CacheFilePy = GetOwner<pkgCache*>(Owner); + // get the pkgCacheFile from the cachefile + pkgCacheFile *CacheF = GetCpp<pkgCacheFile*>(CacheFilePy); + // and now the depcache + pkgDepCache *depcache = (pkgDepCache *)(*CacheF); + + CppPyObject<pkgDepCache*> *DepCachePyObj; + DepCachePyObj = CppPyObject_NEW<pkgDepCache*>(Owner,type,depcache); + + // Do not delete the underlying pointer, it is managed by the cachefile. + DepCachePyObj->NoDelete = true; + + return HandleErrors(DepCachePyObj); +} + +static char *doc_PkgDepCache = "DepCache(cache: apt_pkg.Cache)\n\n" + "A DepCache() holds extra information on the state of the packages.\n\n" + "The parameter 'cache' refers to an apt_pkg.Cache() object."; +PyTypeObject PyDepCache_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.DepCache", // tp_name + sizeof(CppPyObject<pkgDepCache *>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgDepCache *>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_PkgDepCache, // tp_doc + CppTraverse<pkgDepCache *>, // tp_traverse + CppClear<pkgDepCache *>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgDepCacheMethods, // tp_methods + 0, // tp_members + PkgDepCacheGetSet, // 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 + PkgDepCacheNew, // tp_new +}; + + + + + /*}}}*/ + +#undef VALIDATE_ITERATOR +#define VALIDATE_ITERATOR(I) (void) 0 // FIXME: Need access to depcache of pkgProblemResolver + +// pkgProblemResolver Class /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *PkgProblemResolverNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"depcache",0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, + &Owner) == 0) + return 0; + + pkgDepCache *depcache = GetCpp<pkgDepCache*>(Owner); + pkgProblemResolver *fixer = new pkgProblemResolver(depcache); + CppPyObject<pkgProblemResolver*> *PkgProblemResolverPyObj; + PkgProblemResolverPyObj = CppPyObject_NEW<pkgProblemResolver*>(Owner, + type, + fixer); + HandleErrors(PkgProblemResolverPyObj); + + return PkgProblemResolverPyObj; +} + + +static PyObject *PkgProblemResolverResolve(PyObject *Self,PyObject *Args) +{ + bool res; + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + + char brokenFix=1; + if (PyArg_ParseTuple(Args,"|b",&brokenFix) == 0) + return 0; + + Py_BEGIN_ALLOW_THREADS + res = fixer->Resolve(brokenFix); + Py_END_ALLOW_THREADS + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyObject *PkgProblemResolverResolveByKeep(PyObject *Self,PyObject *Args) +{ + bool res; + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Py_BEGIN_ALLOW_THREADS + res = fixer->ResolveByKeep(); + Py_END_ALLOW_THREADS + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyObject *PkgProblemResolverProtect(PyObject *Self,PyObject *Args) +{ + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + fixer->Protect(Pkg); + Py_INCREF(Py_None); + return HandleErrors(Py_None); + +} +static PyObject *PkgProblemResolverRemove(PyObject *Self,PyObject *Args) +{ + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + fixer->Remove(Pkg); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgProblemResolverClear(PyObject *Self,PyObject *Args) +{ + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PyPackage_Type,&PackageObj) == 0) + return 0; + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + VALIDATE_ITERATOR(Pkg); + fixer->Clear(Pkg); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *PkgProblemResolverKeepPhasedUpdates(PyObject *Self,PyObject *Args) +{ + bool res; + pkgProblemResolver *fixer = GetCpp<pkgProblemResolver *>(Self); + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Py_BEGIN_ALLOW_THREADS + res = fixer->KeepPhasedUpdates(); + Py_END_ALLOW_THREADS + + return HandleErrors(PyBool_FromLong(res)); +} + + +static PyMethodDef PkgProblemResolverMethods[] = +{ + // config + {"protect", PkgProblemResolverProtect, METH_VARARGS, + "protect(pkg: apt_pkg.Package)\n\n" + "Mark the package as protected in the resolver, meaning that its\n" + "state will not be changed."}, + {"remove", PkgProblemResolverRemove, METH_VARARGS, + "remove(pkg: apt_pkg.Package)\n\n" + "Mark the package for removal in the resolver."}, + {"clear", PkgProblemResolverClear, METH_VARARGS, + "clear(pkg: apt_pkg.Package)\n\n" + "Revert the actions done by protect()/remove() on the package."}, + + // Actions + {"resolve", PkgProblemResolverResolve, METH_VARARGS, + "resolve([fix_broken: bool = True]) -> bool\n\n" + "Try to intelligently resolve problems by installing and removing\n" + "packages. If 'fix_broken' is True, apt will try to repair broken\n" + "dependencies of installed packages."}, + {"resolve_by_keep", PkgProblemResolverResolveByKeep, METH_VARARGS, + "resolve_by_keep() -> bool\n\n" + "Try to resolve problems only by using keep."}, + {"keep_phased_updates", PkgProblemResolverKeepPhasedUpdates, METH_VARARGS, + "keep_phased_updates() -> bool\n\n" + "Hold back upgrades to phased versions of already installed\n" + "packages, unless they are security updates."}, + {} +}; + +static const char *problemresolver_doc = + "ProblemResolver(depcache: apt_pkg.DepCache)\n\n" + "ProblemResolver objects take care of resolving problems\n" + "with dependencies. They mark packages for installation/\n" + "removal and try to satisfy all dependencies."; +PyTypeObject PyProblemResolver_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.ProblemResolver", // tp_name + sizeof(CppPyObject<pkgProblemResolver *>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgProblemResolver *>,// tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + problemresolver_doc, // tp_doc + CppTraverse<pkgProblemResolver *>, // tp_traverse + CppClear<pkgProblemResolver *>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgProblemResolverMethods, // 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 + PkgProblemResolverNew, // tp_new +}; + + /*}}}*/ + +// pkgActionGroup Class /*{{{*/ +// --------------------------------------------------------------------- + +static const char *actiongroup_release_doc = + "release()\n\n" + "End the scope of this action group. If this is the only action\n" + "group bound to the cache, this will cause any deferred cleanup\n" + "actions to be performed."; +static PyObject *PkgActionGroupRelease(PyObject *Self,PyObject *Args) +{ + pkgDepCache::ActionGroup *ag = GetCpp<pkgDepCache::ActionGroup*>(Self); + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + ag->release(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static const char *actiongroup__enter__doc = + "__enter__() -> ActionGroup\n\n" + "A dummy action which just returns the object itself, so it can\n" + "be used as a context manager."; +static PyObject *PkgActionGroupEnter(PyObject *Self,PyObject *Args) { + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + Py_INCREF(Self); + return Self; +} + +static const char *actiongroup__exit__doc = + "__exit__(*excinfo) -> bool\n\n" + "Same as release(), but for use as a context manager."; +static PyObject *PkgActionGroupExit(PyObject *Self,PyObject *Args) { + pkgDepCache::ActionGroup *ag = GetCpp<pkgDepCache::ActionGroup*>(Self); + if (ag != NULL) + ag->release(); + Py_RETURN_FALSE; +} + +static PyMethodDef PkgActionGroupMethods[] = +{ + {"release", PkgActionGroupRelease, METH_VARARGS, actiongroup_release_doc}, + {"__enter__", PkgActionGroupEnter, METH_VARARGS, actiongroup__enter__doc}, + {"__exit__", PkgActionGroupExit, METH_VARARGS, actiongroup__exit__doc}, + {} +}; + +static PyObject *PkgActionGroupNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"depcache", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, + &Owner) == 0) + return 0; + + pkgDepCache *depcache = GetCpp<pkgDepCache*>(Owner); + pkgDepCache::ActionGroup *group = new pkgDepCache::ActionGroup(*depcache); + CppPyObject<pkgDepCache::ActionGroup*> *PkgActionGroupPyObj; + PkgActionGroupPyObj = CppPyObject_NEW<pkgDepCache::ActionGroup*>(Owner, + type, + group); + HandleErrors(PkgActionGroupPyObj); + + return PkgActionGroupPyObj; + +} + +static char *doc_PkgActionGroup = "ActionGroup(depcache)\n\n" + "Create a new ActionGroup() object. The parameter *depcache* refers to an\n" + "apt_pkg.DepCache() object.\n\n" + "ActionGroups disable certain cleanup actions, so modifying many packages\n" + "is much faster.\n\n" + "ActionGroup() can also be used with the 'with' statement, but be aware\n" + "that the ActionGroup() is active as soon as it is created, and not just\n" + "when entering the context. This means you can write::\n\n" + " with apt_pkg.ActionGroup(depcache):\n" + " depcache.markInstall(pkg)\n\n" + "Once the block of the with statement is left, the action group is \n" + "automatically released from the cache."; + + +PyTypeObject PyActionGroup_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.ActionGroup", // tp_name + sizeof(CppPyObject<pkgDepCache::ActionGroup*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgDepCache::ActionGroup*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_PkgActionGroup, // tp_doc + CppTraverse<pkgDepCache::ActionGroup*>, // tp_traverse + CppClear<pkgDepCache::ActionGroup*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgActionGroupMethods, // 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 + PkgActionGroupNew, // tp_new +}; + + + + /*}}}*/ diff --git a/python/generic.cc b/python/generic.cc new file mode 100644 index 0000000..16f1cce --- /dev/null +++ b/python/generic.cc @@ -0,0 +1,122 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: generic.cc,v 1.1.1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + generic - Some handy functions to make integration a tad simpler + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +using namespace std; + + +#include <apt-pkg/error.h> + /*}}}*/ + +// HandleErrors - This moves errors from _error to Python Exceptions /*{{{*/ +// --------------------------------------------------------------------- +/* We throw away all warnings and only propogate the first error. */ +PyObject *HandleErrors(PyObject *Res) +{ + string Err; + int errcnt = 0; + int wrncnt = 0; + while (_error->empty() == false) + { + string Msg; + bool Type = _error->PopMessage(Msg); + if (errcnt > 0 || wrncnt > 0) + Err.append(", "); + Err.append((Type == true ? "E:" : "W:")); + Err.append(Msg); + if (Type) + ++errcnt; + else + ++wrncnt; + } + if (errcnt > 0) + { + PyErr_SetString(PyAptError,Err.c_str()); + goto err; + } + else if (wrncnt > 0) + { + if (PyErr_WarnEx(PyAptWarning, Err.c_str(), 1) == -1) + goto err; + } + + return Res; +err: + if (Res != 0) + Py_DECREF(Res); + + return nullptr; +} + + /*}}}*/ +// ListToCharChar - Convert a list to an array of char char /*{{{*/ +// --------------------------------------------------------------------- +/* Caller must free the result. 0 on error. */ +const char **ListToCharChar(PyObject *List,bool NullTerm) +{ + // Convert the argument list into a char ** + int Length = PySequence_Length(List); + const char **Res = new const char *[Length + (NullTerm == true?1:0)]; + for (int I = 0; I != Length; I++) + { + PyObject *Itm = PySequence_GetItem(List,I); + Res[I] = PyObject_AsString(Itm); + if (Res[I] == nullptr) { + delete [] Res; + return nullptr; + } + } + if (NullTerm == true) + Res[Length] = 0; + return Res; +} + /*}}}*/ +// CharCharToList - Inverse of the above /*{{{*/ +// --------------------------------------------------------------------- +/* Zero size indicates the list is Null terminated. */ +PyObject *CharCharToList(const char **List,unsigned long Size) +{ + if (Size == 0) + { + for (const char **I = List; *I != 0; I++) + Size++; + } + + // Convert the whole configuration space into a list + PyObject *PList = PyList_New(Size); + for (unsigned long I = 0; I != Size; I++, List++) + PyList_SetItem(PList,I,CppPyString(*List)); + + return PList; +} + /*}}}*/ + +int PyApt_Filename::init(PyObject *object) +{ + this->object = NULL; + this->path = NULL; + +#if PY_MAJOR_VERSION < 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2) + this->path = PyObject_AsString(object); + return this->path ? 1 : 0; +#else + if (PyUnicode_Check(object)) { + object = PyUnicode_EncodeFSDefault(object); + } else if (PyBytes_Check(object)) { + Py_INCREF(object); + } else { + return 0; + } + + this->object = object; + this->path = PyBytes_AS_STRING(this->object); + return 1; +#endif +} diff --git a/python/generic.h b/python/generic.h new file mode 100644 index 0000000..60f9531 --- /dev/null +++ b/python/generic.h @@ -0,0 +1,336 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: generic.h,v 1.4 2002/03/10 05:45:34 mdz Exp $ +/* ###################################################################### + + generic - Some handy functions to make integration a tad simpler + + Python needs this little _HEAD tacked onto the front of the object.. + This complicates the integration with C++. We use some templates to + make that quite transparent to us. It would have been nice if Python + internally used a page from the C++ ref counting book to hide its little + header from the world, but it doesn't. + + The CppPyObject has the target object and the Python header, this is + needed to ensure proper alignment. + GetCpp returns the C++ object from a PyObject. + CppPyObject_NEW creates the Python object and then uses placement new + to init the C++ class.. This is good for simple situations and as an + example on how to do it in other more specific cases. + CppPyObject_Dealloc should be used in the Type as the destructor + function. + HandleErrors converts errors from the internal _error stack into Python + exceptions and makes sure the _error stack is empty. + + ##################################################################### */ + /*}}}*/ +#ifndef GENERIC_H +#define GENERIC_H + +#include <Python.h> +#include <string> +#include <iostream> +#include <new> +#include <langinfo.h> + +/** + * Exception class for almost all Python errors + */ +extern PyObject *PyAptError; +extern PyObject *PyAptWarning; +/** + * Exception class for invalidated cache objects. + */ +extern PyObject *PyAptCacheMismatchError; + +#if PYTHON_API_VERSION < 1013 +typedef int Py_ssize_t; +#endif + +/* Define compatibility for Python 3. + * + * We will use the names PyString_* to refer to the default string type + * of the current Python version (PyString on 2.X, PyUnicode on 3.X). + * + * When we really need unicode strings, we will use PyUnicode_* directly, as + * long as it exists in Python 2 and Python 3. + * + * When we want bytes in Python 3, we use PyBytes*_ instead of PyString_* and + * define aliases from PyBytes_* to PyString_* for Python 2. + */ + +#if PY_MAJOR_VERSION >= 3 +#define PyString_Check PyUnicode_Check +#define PyString_FromString PyUnicode_FromString +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyString_AsString PyUnicode_AsString +#define PyString_FromFormat PyUnicode_FromFormat +#define PyString_Type PyUnicode_Type +#define PyInt_Check PyLong_Check +#define PyInt_AsLong PyLong_AsLong +#define PyInt_FromLong PyLong_FromLong +#endif + +static inline const char *PyUnicode_AsString(PyObject *op) { + // Convert to bytes object, using the default encoding. +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + return PyUnicode_AsUTF8(op); +#else + // Use Python-internal API, there is no other way to do this + // without a memory leak. + PyObject *bytes = _PyUnicode_AsDefaultEncodedString(op, 0); + return bytes ? PyBytes_AS_STRING(bytes) : 0; +#endif +} + +// Convert any type of string based object to a const char. +#if PY_MAJOR_VERSION < 3 +static inline const char *PyObject_AsString(PyObject *object) { + if (PyBytes_Check(object)) + return PyBytes_AsString(object); + else if (PyUnicode_Check(object)) + return PyUnicode_AsString(object); + else + PyErr_SetString(PyExc_TypeError, "Argument must be str."); + return 0; +} +#else +static inline const char *PyObject_AsString(PyObject *object) { + if (PyUnicode_Check(object) == 0) { + PyErr_SetString(PyExc_TypeError, "Argument must be str."); + return 0; + } + return PyUnicode_AsString(object); +} +#endif + +template <class T> struct CppPyObject : public PyObject +{ + // We are only using CppPyObject and friends as dumb structs only, ie the + // c'tor is never called. + // However if T doesn't have a default c'tor C++ doesn't generate one for + // CppPyObject (since it can't know how it should initialize Object). + // + // This causes problems then in CppPyObject, for which C++ can't create + // a c'tor that calls the base class c'tor (which causes a compilation + // error). + // So basically having the c'tor here removes the need for T to have a + // default c'tor, which is not always desireable. + CppPyObject() { }; + + // The owner of the object. The object keeps a reference to it during its + // lifetime. + PyObject *Owner; + + // Flag which causes the underlying object to not be deleted. + bool NoDelete; + + // The underlying C++ object. + T Object; +}; + +template <class T> +inline T &GetCpp(PyObject *Obj) +{ + return ((CppPyObject<T> *)Obj)->Object; +} + +template <class T> +inline PyObject *GetOwner(PyObject *Obj) +{ + return ((CppPyObject<T> *)Obj)->Owner; +} + + +template <class T> +inline CppPyObject<T> *CppPyObject_NEW(PyObject *Owner,PyTypeObject *Type) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject<T> *New = (CppPyObject<T>*)Type->tp_alloc(Type, 0); + new (&New->Object) T; + New->Owner = Owner; + Py_XINCREF(Owner); + return New; +} + +template <class T,class A> +inline CppPyObject<T> *CppPyObject_NEW(PyObject *Owner, PyTypeObject *Type,A const &Arg) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== ALLOCATING " << Type->tp_name << "+ ===\n"; + #endif + CppPyObject<T> *New = (CppPyObject<T>*)Type->tp_alloc(Type, 0); + new (&New->Object) T(Arg); + New->Owner = Owner; + Py_XINCREF(Owner); + return New; +} + +// Traversal and Clean for objects +template <class T> +int CppTraverse(PyObject *self, visitproc visit, void* arg) { + Py_VISIT(((CppPyObject<T> *)self)->Owner); + return 0; +} + +template <class T> +int CppClear(PyObject *self) { + Py_CLEAR(((CppPyObject<T> *)self)->Owner); + return 0; +} + +template <class T> +void CppDealloc(PyObject *iObj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "+ ===\n"; + #endif + if (iObj->ob_type->tp_flags & Py_TPFLAGS_HAVE_GC) + PyObject_GC_UnTrack(iObj); + CppPyObject<T> *Obj = (CppPyObject<T> *)iObj; + if (!((CppPyObject<T>*)Obj)->NoDelete) + Obj->Object.~T(); + CppClear<T>(iObj); + iObj->ob_type->tp_free(iObj); +} + + +template <class T> +void CppDeallocPtr(PyObject *iObj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << iObj->ob_type->tp_name << "*+ ===\n"; + #endif + if (iObj->ob_type->tp_flags & Py_TPFLAGS_HAVE_GC) + PyObject_GC_UnTrack(iObj); + CppPyObject<T> *Obj = (CppPyObject<T> *)iObj; + if (!((CppPyObject<T>*)Obj)->NoDelete) { + delete Obj->Object; + Obj->Object = NULL; + } + CppClear<T>(iObj); + iObj->ob_type->tp_free(iObj); +} + +inline PyObject *CppPyString(const std::string &Str) +{ + return PyString_FromStringAndSize(Str.c_str(),Str.length()); +} + +inline PyObject *CppPyString(const char *Str) +{ + if (Str == 0) + return PyString_FromString(""); + return PyString_FromString(Str); +} + +inline PyObject *CppPyLocaleString(const std::string &Str) +{ + char const * const codeset = nl_langinfo(CODESET); + return PyUnicode_Decode(Str.c_str(), Str.length(), codeset, "replace"); +} + +#if PY_MAJOR_VERSION >= 3 +static inline PyObject *CppPyPath(const std::string &path) +{ + return PyUnicode_DecodeFSDefaultAndSize(path.c_str(), path.length()); +} + +static inline PyObject *CppPyPath(const char *path) +{ + if (path == nullptr) + path = ""; + return PyUnicode_DecodeFSDefault(path); +} +#else +template<typename T> static inline PyObject *CppPyPath(T path) { + return CppPyString(path); +} +#endif + +// Convert _error into Python exceptions +PyObject *HandleErrors(PyObject *Res = 0); + +// Convert a list of strings to a char ** +const char **ListToCharChar(PyObject *List,bool NullTerm = false); +PyObject *CharCharToList(const char **List,unsigned long Size = 0); + +/* Happy number conversion, thanks to overloading */ +inline PyObject *MkPyNumber(unsigned long long o) { return PyLong_FromUnsignedLongLong(o); } +inline PyObject *MkPyNumber(unsigned long o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned int o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(unsigned char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(long long o) { return PyLong_FromLongLong(o); } +inline PyObject *MkPyNumber(long o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(int o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(signed char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(double o) { return PyFloat_FromDouble(o); } + +# define _PyAptObject_getattro 0 + + +/** + * Magic class for file name handling + * + * This manages decoding file names from Python objects; bytes and unicode + * objects. On Python 2, this does the same conversion as PyObject_AsString, + * on Python3, it uses PyUnicode_EncodeFSDefault for unicode objects. + */ +class PyApt_Filename { +public: + PyObject *object; + const char *path; + + PyApt_Filename() { + object = NULL; + path = NULL; + } + + int init(PyObject *object); + + ~PyApt_Filename() { + Py_XDECREF(object); + } + + static int Converter(PyObject *object, void *out) { + return static_cast<PyApt_Filename *>(out)->init(object); + } + + operator const char *() { + return path; + } + operator const std::string() { + return path; + } + + const char *operator=(const char *path) { + return this->path = path; + } +}; + + +/** + * Basic smart pointer to hold initial objects. + * + * This is like a std::unique_ptr<PyObject, decltype(&Py_DecRef)> to some extend, + * but it is for initialization only, and hence will also clear out any members + * in case it deletes the instance (the error case). + */ +template <class T, bool clear=true> struct PyApt_UniqueObject { + T *self; + explicit PyApt_UniqueObject(T *self) : self(self) { } + ~PyApt_UniqueObject() { reset(NULL); } + void reset(T *newself) { if (clear && self && Py_TYPE(self)->tp_clear) Py_TYPE(self)->tp_clear(self); Py_XDECREF(self); self = newself; } + PyApt_UniqueObject<T> operator =(PyApt_UniqueObject<T>) = delete; + bool operator ==(void *other) { return self == other; } + T *operator ->() { return self; } + T *get() { return self; } + T *release() { T *ret = self; self = NULL; return ret; } +}; +#endif diff --git a/python/hashes.cc b/python/hashes.cc new file mode 100644 index 0000000..9f3fb46 --- /dev/null +++ b/python/hashes.cc @@ -0,0 +1,135 @@ +/* hashes.cc - Wrapper around apt-pkg's Hashes. + * + * Copyright 2009 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 "generic.h" +#include "apt_pkgmodule.h" +#include <apt-pkg/hashes.h> + +static PyObject *hashes_new(PyTypeObject *type,PyObject *args, + PyObject *kwds) +{ + return CppPyObject_NEW<Hashes>(NULL, type); +} + +static int hashes_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *object = 0; + int Fd; + char *kwlist[] = {"object", NULL}; + + if (PyArg_ParseTupleAndKeywords(args, kwds, "|O:__init__", kwlist, + &object) == 0) + return -1; + if (object == 0) + return 0; + Hashes &hashes = GetCpp<Hashes>(self); + + if (PyBytes_Check(object) != 0) { + char *s; + Py_ssize_t len; + PyBytes_AsStringAndSize(object, &s, &len); + Py_BEGIN_ALLOW_THREADS + hashes.Add((const unsigned char*)s, len); + Py_END_ALLOW_THREADS + } + else if ((Fd = PyObject_AsFileDescriptor(object)) != -1) { + struct stat St; + bool err = false; + Py_BEGIN_ALLOW_THREADS + err = fstat(Fd, &St) != 0 || hashes.AddFD(Fd, St.st_size) == false; + Py_END_ALLOW_THREADS + if (err) { + PyErr_SetFromErrno(PyAptError); + return -1; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "__init__() only understand bytes and files"); + return -1; + } + return 0; +} + +static PyObject *hashes_get_hashes(PyObject *self, void*) +{ + auto py = CppPyObject_NEW<HashStringList>(nullptr, &PyHashStringList_Type); + + py->Object = GetCpp<Hashes>(self).GetHashStringList(); + return py; +} + + +static PyGetSetDef hashes_getset[] = { + {"hashes",hashes_get_hashes,0, + "A :class:`HashStringList` of all hashes.\n\n" + ".. versionadded:: 1.1"}, + {} +}; + +static char *hashes_doc = + "Hashes([object: (bytes, file)])\n\n" + "Calculate hashes for the given object. It can be used to create all\n" + "supported hashes for a file.\n\n" + "The parameter *object* can be a bytestring, an object providing the\n" + "fileno() method, or an integer describing a file descriptor."; + +PyTypeObject PyHashes_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Hashes", // tp_name + sizeof(CppPyObject<Hashes>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<Hashes>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE, + hashes_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + hashes_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + hashes_init, // tp_init + 0, // tp_alloc + hashes_new, // tp_new +}; diff --git a/python/hashstring.cc b/python/hashstring.cc new file mode 100644 index 0000000..01f14a0 --- /dev/null +++ b/python/hashstring.cc @@ -0,0 +1,182 @@ +/* hashstring.cc - Wrapper around HashString + * + * Copyright 2009 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 "generic.h" +#include "apt_pkgmodule.h" +#include <apt-pkg/hashes.h> + +static PyObject *hashstring_new(PyTypeObject *type,PyObject *Args, + PyObject *kwds) +{ + char *Type = NULL; + char *Hash = NULL; + char *kwlist[] = {"type", "hash", NULL}; + if (PyArg_ParseTupleAndKeywords(Args, kwds, "s|s:__new__", kwlist, &Type, + &Hash) == 0) + return 0; + CppPyObject<HashString*> *PyObj = CppPyObject_NEW<HashString*>(NULL, type); + if (Hash) + PyObj->Object = new HashString(Type,Hash); + else // Type is the combined form now (i.e. type:hash) + PyObj->Object = new HashString(Type); + return PyObj; +} + +static PyObject *hashstring_repr(PyObject *self) +{ + HashString *hash = GetCpp<HashString*>(self); + return PyString_FromFormat("<%s object: \"%s\">", self->ob_type->tp_name, + hash->toStr().c_str()); +} + +static PyObject *hashstring_str(PyObject *self) +{ + const HashString *hash = GetCpp<HashString*>(self); + return CppPyString(hash->toStr()); +} + +static PyObject *hashstring_get_hashtype(PyObject *self) +{ + const HashString *hash = GetCpp<HashString*>(self); + return CppPyString(hash->HashType()); +} + +static PyObject *hashstring_get_usable(PyObject *self) +{ + const HashString *hash = GetCpp<HashString*>(self); + return PyBool_FromLong(hash->usable()); +} + +static PyObject *hashstring_get_hashvalue(PyObject *self) +{ + const HashString *hash = GetCpp<HashString*>(self); + return CppPyString(hash->HashValue()); +} + +static char *hashstring_verify_file_doc = + "verify_file(filename: str) -> bool\n\n" + "Verify that the file indicated by filename matches the hash."; + +static PyObject *hashstring_verify_file(PyObject *self,PyObject *args) +{ + const HashString *hash = GetCpp<HashString*>(self); + char *filename; + if (PyArg_ParseTuple(args, "s:verify_file", &filename) == 0) + return 0; + return PyBool_FromLong(hash->VerifyFile(filename)); +} + +static PyMethodDef hashstring_methods[] = { + {"verify_file",hashstring_verify_file,METH_VARARGS, + hashstring_verify_file_doc}, + {NULL} +}; + +static PyGetSetDef hashstring_getset[] = { + {"hashtype",(getter)hashstring_get_hashtype,0, + "The type of the hash, as a string (possible: MD5Sum,SHA1,SHA256)."}, + {"hashvalue",(getter)hashstring_get_hashvalue,0, + "The value of the hash, as a hexadecimal string\n" + "\n" + ".. versionadded:: 1.9.0"}, + {"usable",(getter)hashstring_get_usable,0, + "True if the hashstring is a trusted hash type."}, + {NULL} +}; + +static PyObject *hashstring_richcompare(PyObject *obj1, PyObject *obj2, int op) +{ + if (!PyObject_TypeCheck(obj1, &PyHashString_Type)) + return PyErr_SetString(PyExc_TypeError, "Expected HashString"), nullptr; + if (!PyObject_TypeCheck(obj2, &PyHashString_Type)) + return PyErr_SetString(PyExc_TypeError, "Expected HashString"), nullptr; + + const HashString *a = GetCpp<HashString*>(obj1); + const HashString *b = GetCpp<HashString*>(obj2); + PyObject *result = Py_False; + + switch (op) { + case Py_LT: + case Py_GT: + result = Py_False; + break; + case Py_LE: + case Py_GE: + case Py_EQ: + result = *a == *b ? Py_True : Py_False; + break; + case Py_NE: + result = *a != *b ? Py_True : Py_False; + break; + } + + Py_INCREF(result); + return result; + } + +static char *hashstring_doc = + "HashString(type, hash) OR HashString('type:hash')\n\n" + "Create a new HashString object. The first form allows you to specify\n" + "a type and a hash, and the second form a single string where type and\n" + "hash are separated by a colon, e.g.::\n\n" + " HashString('MD5Sum', '6cc1b6e6655e3555ac47e5b5fe26d04e')\n\n" + "Valid options for 'type' are: MD5Sum, SHA1, SHA256."; +PyTypeObject PyHashString_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.HashString", // tp_name + sizeof(CppPyObject<HashString*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<HashString*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + hashstring_repr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + hashstring_str, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE, + hashstring_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + hashstring_richcompare, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + hashstring_methods, // tp_methods + 0, // tp_members + hashstring_getset, // 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 + hashstring_new, // tp_new +}; diff --git a/python/hashstringlist.cc b/python/hashstringlist.cc new file mode 100644 index 0000000..f25f502 --- /dev/null +++ b/python/hashstringlist.cc @@ -0,0 +1,220 @@ +/* hashstringlist.cc - Wrapper around apt-pkg's Hashes. + * + * Copyright 2015 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 "generic.h" +#include "apt_pkgmodule.h" +#include <apt-pkg/hashes.h> + +static PyObject *hashstringlist_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + return CppPyObject_NEW<HashStringList> (nullptr, type); +} + +static int hashstringlist_init(PyObject *self, PyObject *args, + PyObject *kwds) +{ + char *kwlist[] = { NULL }; + + if (PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist) == 0) + return -1; + + return 0; +} + + +static const char hashstringlist_find_doc[] = + "find(type: str = \"\") -> HashString\n\n" + "Find a hash of the given type, or the best one, if the argument\n" + "is empty or not specified."; +static PyObject *hashstringlist_find(PyObject *self, PyObject *args) +{ + char *type = ""; + + if (PyArg_ParseTuple(args, "|s", &type) == 0) + return 0; + + const HashString *hsf = GetCpp<HashStringList>(self).find(type); + if (hsf == nullptr) + return PyErr_Format(PyExc_KeyError, "Could not find hash type %s", type); + + + return HandleErrors(PyHashString_FromCpp(new HashString(*hsf), true, nullptr)); +} + +static const char hashstringlist_append_doc[] = + "append(object: HashString)\n\n" + "Append the given HashString to this list."; +static PyObject *hashstringlist_append(PyObject *self, PyObject *args) +{ + PyObject *o; + + if (PyArg_ParseTuple(args, "O!", &PyHashString_Type, &o) == 0) + return 0; + + GetCpp<HashStringList>(self).push_back(*PyHashString_ToCpp(o)); + Py_RETURN_NONE; +} + +static const char hashstringlist_verify_file_doc[] = + "verify_file(filename: str) -> bool\n\n" + "Verify that the file with the given name matches all hashes in\n" + "the list."; +static PyObject *hashstringlist_verify_file(PyObject *self, PyObject *args) +{ + PyApt_Filename filename; + + if (PyArg_ParseTuple(args, "O&", PyApt_Filename::Converter, &filename) == 0) + return 0; + + bool res = GetCpp<HashStringList>(self).VerifyFile(filename); + + PyObject *PyRes = PyBool_FromLong(res); + return HandleErrors(PyRes); +} + +static PyObject *hashstringlist_get_file_size(PyObject *self, void*) { + return MkPyNumber(GetCpp<HashStringList>(self).FileSize()); +} +static PyObject *hashstringlist_get_usable(PyObject *self, void*) { + return PyBool_FromLong(GetCpp<HashStringList>(self).usable()); +} + +static int hashstringlist_set_file_size(PyObject *self, PyObject *value, void *) { + if (PyLong_Check(value)) { + if (PyLong_AsUnsignedLongLong(value) == (unsigned long long) -1) { + return 1; + } + GetCpp<HashStringList>(self).FileSize(PyLong_AsUnsignedLongLong(value)); + } else if (PyInt_Check(value)) { + if (PyInt_AsLong(value) < 0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_OverflowError, + "The file_size value must be positive"); + return 1; + } + GetCpp<HashStringList>(self).FileSize(PyInt_AsLong(value)); + } else { + PyErr_SetString(PyExc_TypeError, + "The file_size value must be an integer or long"); + return 1; + } + + return 0; +} + +/* The same for groups */ +static Py_ssize_t hashstringlist_len(PyObject *self) +{ + return GetCpp <HashStringList>(self).size(); +} + +static PyObject *hashstringlist_getitem(PyObject *iSelf, Py_ssize_t index) +{ + HashStringList &self = GetCpp<HashStringList>(iSelf); + + if (index < 0 || (size_t) index >= self.size()) + return PyErr_Format(PyExc_IndexError, "Out of range: %zd", index); + + /* Copy over, safer than using a reference to the vector element */ + HashString *hs = new HashString; + (*hs) = *(self.begin() + index); + + return PyHashString_FromCpp(hs, true, nullptr); +} + +static PySequenceMethods hashstringlist_seq_methods = { + hashstringlist_len, + 0, // concat + 0, // repeat + hashstringlist_getitem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +static PyMethodDef hashstringlist_methods[] = +{ + {"verify_file",hashstringlist_verify_file,METH_VARARGS, + hashstringlist_verify_file_doc}, + {"find",hashstringlist_find,METH_VARARGS, + hashstringlist_find_doc}, + {"append",hashstringlist_append,METH_VARARGS, + hashstringlist_append_doc}, + {} +}; + +static PyGetSetDef hashstringlist_getset[] = { + {"file_size",hashstringlist_get_file_size,hashstringlist_set_file_size, + "If a file size is part of the list, return it, otherwise 0."}, + {"usable",hashstringlist_get_usable,nullptr, + "True if at least one safe/trusted hash is in the list."}, + {} +}; + + +static char *hashstringlist_doc = + "HashStringList()\n\n" + "Manage a list of HashStrings.\n\n" + "The list knows which hash is the best and provides convenience\n" + "methods for file verification.\n\n" + ".. versionadded:: 1.1"; + +PyTypeObject PyHashStringList_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.HashStringList", // tp_name + sizeof(CppPyObject<HashStringList>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<HashStringList>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &hashstringlist_seq_methods, // 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 + hashstringlist_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + hashstringlist_methods, // tp_methods + 0, // tp_members + hashstringlist_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + hashstringlist_init, // tp_init + 0, // tp_alloc + hashstringlist_new, // tp_new +}; diff --git a/python/indexfile.cc b/python/indexfile.cc new file mode 100644 index 0000000..423e2e3 --- /dev/null +++ b/python/indexfile.cc @@ -0,0 +1,130 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: indexfile.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ +/* ###################################################################### + + pkgIndexFile - Wrapper for the pkgIndexFilefunctions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/indexfile.h> + +#include <Python.h> + +static PyObject *IndexFileArchiveURI(PyObject *Self,PyObject *Args) +{ + pkgIndexFile *File = GetCpp<pkgIndexFile*>(Self); + PyApt_Filename path; + + if (PyArg_ParseTuple(Args, "O&", PyApt_Filename::Converter, &path) == 0) + return 0; + return HandleErrors(CppPyString(File->ArchiveURI(path).c_str())); +} + +static PyMethodDef IndexFileMethods[] = +{ + {"archive_uri",IndexFileArchiveURI,METH_VARARGS, + "archive_uri(path: str) -> str\n\n" + "Return the URI to the given path in the archive."}, + {} +}; + +#define File (GetCpp<pkgIndexFile*>(Self)) +static PyObject *IndexFileGetLabel(PyObject *Self,void*) { + return CppPyString(File->GetType()->Label); +} +static PyObject *IndexFileGetDescribe(PyObject *Self,void*) { + return CppPyString(File->Describe().c_str()); +} +static PyObject *IndexFileGetExists(PyObject *Self,void*) { + return PyBool_FromLong((File->Exists())); +} +static PyObject *IndexFileGetHasPackages(PyObject *Self,void*) { + return PyBool_FromLong((File->HasPackages())); +} +static PyObject *IndexFileGetSize(PyObject *Self,void*) { + return MkPyNumber((File->Size())); +} +static PyObject *IndexFileGetIsTrusted(PyObject *Self,void*) { + return PyBool_FromLong((File->IsTrusted())); +} +#undef File + +#define S(x) (x ? x : "") +static PyObject *IndexFileRepr(PyObject *Self) +{ + pkgIndexFile *File = GetCpp<pkgIndexFile*>(Self); + return PyString_FromFormat("<pkIndexFile object: " + "Label:'%s' Describe='%s' Exists='%i' " + "HasPackages='%i' Size='%lu' " + "IsTrusted='%i' ArchiveURI='%s'>", + S(File->GetType()->Label), File->Describe().c_str(), File->Exists(), + File->HasPackages(), File->Size(), + File->IsTrusted(), File->ArchiveURI("").c_str()); +} +#undef S + +static PyGetSetDef IndexFileGetSet[] = { + {"describe",IndexFileGetDescribe,0, + "A string describing the index file."}, + {"exists",IndexFileGetExists,0, + "A boolean value determining whether the index file exists."}, + {"has_packages",IndexFileGetHasPackages,0, + "A boolean value determining whether the index file has packages."}, + {"is_trusted",IndexFileGetIsTrusted,0, + "A boolean value determining whether the file can be trusted; e.g.\n" + "because it is from a source with a GPG signed Release file."}, + {"label",IndexFileGetLabel,0, + "The label of the index file."}, + {"size",IndexFileGetSize,0, + "The size of the files, measured in bytes."}, + {} +}; + +static const char *indexfile_doc = + "Represent an index file, i.e. package indexes, translation indexes,\n" + "and source indexes."; + +PyTypeObject PyIndexFile_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.IndexFile", // tp_name + sizeof(CppPyObject<pkgIndexFile*>), // tp_basicsize + 0, // tp_itemsize + // Methods + // Not ..Ptr, because the pointer is managed somewhere else. + CppDeallocPtr<pkgIndexFile*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + IndexFileRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + indexfile_doc, // tp_doc + CppTraverse<pkgIndexFile*>, // tp_traverse + CppClear<pkgIndexFile*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + IndexFileMethods, // tp_methods + 0, // tp_members + IndexFileGetSet, // tp_getset +}; + + + + diff --git a/python/lock.cc b/python/lock.cc new file mode 100644 index 0000000..009605e --- /dev/null +++ b/python/lock.cc @@ -0,0 +1,268 @@ +/* + * lock.cc - Context managers for implementing locking. + * + * Copyright 2009 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-pkg/init.h> +#include <apt-pkg/error.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/pkgsystem.h> +#include "generic.h" + +static PyObject *systemlock_exit(PyObject *self, PyObject *args) +{ + + PyObject *exc_type = 0; + PyObject *exc_value = 0; + PyObject *traceback = 0; + if (!PyArg_UnpackTuple(args, "__exit__", 3, 3, &exc_type, &exc_value, + &traceback)) { + return 0; + } + + if (_system->UnLock() == 0) { + // The unlock failed. If no exception happened within the suite, we + // will raise an error here. Otherwise, we just display the error, so + // Python can handle the original exception instead. + HandleErrors(); + if (exc_type == Py_None) + return NULL; + else + PyErr_WriteUnraisable(self); + } + // Return False, as required by the context manager protocol. + Py_RETURN_FALSE; +} + +static PyObject *systemlock_enter(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + if (!_system->Lock()) + return HandleErrors(); + Py_INCREF(self); + return self; +} + +static PyObject *systemlock_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + if (_system == 0) { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + return PyType_GenericNew(type,args,kwds); +} + +static PyMethodDef systemlock_methods[] = { + {"__enter__",systemlock_enter,METH_VARARGS,"Lock the system."}, + {"__exit__",systemlock_exit,METH_VARARGS,"Unlock the system."}, + {NULL} +}; + +static char *systemlock_doc = "SystemLock()\n\n" + "Context manager for locking the package system. The lock is established\n" + "as soon as the method __enter__() is called. It is released when\n" + "__exit__() is called.\n\n" + "This should be used via the 'with' statement, for example:\n\n" + " with apt_pkg.SystemLock():\n" + " ...\n\n" + "Once the block is left, the lock is released automatically. The object\n" + "can be used multiple times:\n\n" + " lock = apt_pkg.SystemLock()\n" + " with lock:\n" + " ...\n" + " with lock:\n" + " ...\n\n"; + +PyTypeObject PySystemLock_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.SystemLock", // tp_name + 0, // tp_basicsize + 0, // tp_itemsize + // Methods + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE), + systemlock_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + systemlock_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 + systemlock_new, // tp_new +}; + + +/** + * File Based locking. + * + * The counter is increased by every call to filelock_enter() and decreased by + * every call to filelock_exit(). When the counter reaches 0, the underlying + * file descriptor is closed. + * + * Members: + * @member char* filename The name of the file + * @member int lock_count How many times we have locked it. + * @member int fd The filedescriptor returned by GetLock() or 0. + */ +struct filelock_object { + PyObject_HEAD + char *filename; + int lock_count; + int fd; +}; + +static PyObject *filelock_enter(filelock_object *self, PyObject *args) +{ + self->lock_count++; + // If we have no lock yet, get a lock. + if (self->lock_count == 1) { + self->fd = GetLock(self->filename, true); + if (self->fd == -1) { + self->lock_count--; + return HandleErrors(); + } + } + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject *filelock_exit(filelock_object *self, PyObject *args) +{ + // Count down the lock_count, if it is less than 0, reset it to 0. + self->lock_count--; + if (self->lock_count < 0) + self->lock_count = 0; + if (self->lock_count == 0 && self->fd != 0 && close(self->fd) == -1) { + return PyErr_SetFromErrno(PyExc_OSError); + } + Py_RETURN_FALSE; +} + +static PyObject *filelock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyApt_Filename filename; + char *kwlist[] = {"filename", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O&:__init__", kwlist, + PyApt_Filename::Converter, + &filename) == 0) { + return NULL; + } + filelock_object *self = (filelock_object *)type->tp_alloc(type, 0); + // Copy the string into the object. + self->filename = new char[strlen(filename) + 1]; + strcpy(self->filename, filename); + return (PyObject *)self; +} + +static void filelock_dealloc(filelock_object *self) +{ + delete[] self->filename; + ((PyObject*)self)->ob_type->tp_free(self); +} + +static PyMethodDef filelock_methods[] = { + {"__enter__",(PyCFunction)filelock_enter,METH_VARARGS,"Lock the system."}, + {"__exit__",(PyCFunction)filelock_exit,METH_VARARGS,"Unlock the system."}, + {NULL} +}; + +static char *filelock_doc = "FileLock(filename: str)\n\n" + "Context manager for locking using a file. The lock is established\n" + "as soon as the method __enter__() is called. It is released when\n" + "__exit__() is called.\n\n" + "This should be used via the 'with' statement, for example:\n\n" + " with apt_pkg.FileLock(filename):\n" + " ...\n\n" + "Once the block is left, the lock is released automatically. The object\n" + "can be used multiple times:\n\n" + " lock = apt_pkg.FileLock(filename)\n" + " with lock:\n" + " ...\n" + " with lock:\n" + " ...\n\n"; + +PyTypeObject PyFileLock_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.FileLock", // tp_name + sizeof(filelock_object), // tp_basicsize + 0, // tp_itemsize + // Methods + destructor(filelock_dealloc), // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE), + filelock_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + filelock_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 + filelock_new, // tp_new +}; diff --git a/python/metaindex.cc b/python/metaindex.cc new file mode 100644 index 0000000..abbcb8a --- /dev/null +++ b/python/metaindex.cc @@ -0,0 +1,117 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: metaindex.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ +/* ###################################################################### + + metaindex - Wrapper for the metaIndex functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/metaindex.h> + +#include <Python.h> + +static PyObject *MetaIndexGetURI(PyObject *Self,void*) { + metaIndex *meta = GetCpp<metaIndex*>(Self); + return CppPyString(meta->GetURI().c_str()); +} + +static PyObject *MetaIndexGetDist(PyObject *Self,void*) { + metaIndex *meta = GetCpp<metaIndex*>(Self); + return CppPyString(meta->GetDist().c_str()); +} + +static PyObject *MetaIndexGetIsTrusted(PyObject *Self,void*) { + metaIndex *meta = GetCpp<metaIndex*>(Self); + return PyBool_FromLong((meta->IsTrusted())); +} + +static PyObject *MetaIndexGetType(PyObject *Self,void*) { + metaIndex *meta = GetCpp<metaIndex*>(Self); + return CppPyString(meta->GetType()); +} + +static PyObject *MetaIndexGetIndexFiles(PyObject *Self,void*) { + metaIndex *meta = GetCpp<metaIndex*>(Self); + PyObject *List = PyList_New(0); + std::vector<pkgIndexFile *> *indexFiles = meta->GetIndexFiles(); + for (std::vector<pkgIndexFile *>::const_iterator I = indexFiles->begin(); + I != indexFiles->end(); I++) + { + CppPyObject<pkgIndexFile*> *Obj; + Obj = CppPyObject_NEW<pkgIndexFile*>(Self, &PyIndexFile_Type,*I); + // Do not delete pkgIndexFile*, they are managed by metaIndex. + Obj->NoDelete = true; + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyGetSetDef MetaIndexGetSet[] = { + {"dist",MetaIndexGetDist,0,"The distribution, as a string."}, + {"index_files",MetaIndexGetIndexFiles,0, + "A list of all IndexFile objects associated with this meta index."}, + {"is_trusted",MetaIndexGetIsTrusted,0, + "A boolean value determining whether the file can be trusted."}, + {"uri",MetaIndexGetURI,0, + "The uri the meta index is located at."}, + {"type",MetaIndexGetType,0, + "The type of the meta index."}, + {} +}; + +#define S(x) (x ? x : "") +static PyObject *MetaIndexRepr(PyObject *Self) +{ + metaIndex *meta = GetCpp<metaIndex*>(Self); + return PyString_FromFormat("<%s object: type='%s', uri:'%s' dist='%s' " + "is_trusted='%i'>", Self->ob_type->tp_name, + S(meta->GetType()), meta->GetURI().c_str(), + meta->GetDist().c_str(), meta->IsTrusted()); +} +#undef S + + +static const char *metaindex_doc = + "Provide information on meta-indexes (i.e. Release files), such as\n" + "whether they are trusted or their URI."; + +PyTypeObject PyMetaIndex_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.MetaIndex", // tp_name + sizeof(CppPyObject<metaIndex*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<metaIndex*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + MetaIndexRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + metaindex_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + MetaIndexGetSet, // tp_getset +}; diff --git a/python/orderlist.cc b/python/orderlist.cc new file mode 100644 index 0000000..d0ea184 --- /dev/null +++ b/python/orderlist.cc @@ -0,0 +1,317 @@ +/* + * orderlist.cc - Wrapper around pkgOrderList + * + * 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/orderlist.h> + +struct PyOrderList : CppPyObject<pkgOrderList*> { + pkgCache::PkgIterator current; + int nextIndex; +}; + +static PyObject *order_list_new(PyTypeObject *type,PyObject *args, + PyObject *kwds) +{ + PyObject *pyDepCache = NULL; + char *kwlist[] = {"depcache", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, + &PyDepCache_Type, &pyDepCache) + == 0) + return 0; + + pkgDepCache *depCache = PyDepCache_ToCpp(pyDepCache); + return PyOrderList_FromCpp(new pkgOrderList(depCache), true, + pyDepCache); +} + +static const char order_list_append_doc[] = + "append(pkg: Package)\n\n" + "Append a package to the end of the list."; +static PyObject *order_list_append(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPackage = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPackage) == 0) + return 0; + + list->push_back(PyPackage_ToCpp(pyPackage)); + Py_RETURN_NONE; +} + +static const char order_list_score_doc[] = + "score(pkg: Package) -> int\n\n" + "Return the score of the package."; +static PyObject *order_list_score(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPackage = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPackage) == 0) + return 0; + + return MkPyNumber(list->Score(PyPackage_ToCpp(pyPackage))); +} + +static const char order_list_order_critical_doc[] = + "order_critical()\n\n" + "Order by PreDepends only (critical unpack order)."; +static PyObject *order_list_order_critical(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderCritical(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static const char order_list_order_unpack_doc[] = + "order_unpack()\n\n" + "Order the packages for unpacking (see Debian Policy)."; +static PyObject *order_list_order_unpack(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderUnpack(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static const char order_list_order_configure_doc[] = + "order_configure()\n\n" + "Order the packages for configuration (see Debian Policy)."; +static PyObject *order_list_order_configure(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderConfigure(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static bool valid_flags(unsigned int flags) { + return (flags & ~pkgOrderList::Added + & ~pkgOrderList::AddPending + & ~pkgOrderList::Immediate + & ~pkgOrderList::Loop + & ~pkgOrderList::UnPacked + & ~pkgOrderList::Configured + & ~pkgOrderList::Removed + & ~pkgOrderList::InList + & ~pkgOrderList::After + & ~pkgOrderList::States) == 0; +} + +static const char order_list_flag_doc[] = + "flag(pkg: Package, flag: int[, unset_flags: int])\n\n" + "Flag the package, set flags in 'flag' and remove flags in\n" + "'unset_flags'."; +static PyObject *order_list_flag(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + + PyObject *pyPkg = NULL; + unsigned int flags = 0; + unsigned int unset_flags = 0; + if (PyArg_ParseTuple(args, "O!I|I", &PyPackage_Type, &pyPkg, + &flags, &unset_flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + if (!valid_flags(unset_flags)) + return PyErr_Format(PyExc_ValueError, "unset_flags (%u) is" + " not a valid combination of flags.", + unset_flags); + + list->Flag(PyPackage_ToCpp(pyPkg), flags, unset_flags); + + Py_RETURN_NONE; +} + +static const char order_list_is_flag_doc[] = + "is_flag(pkg: Package, flag: int)\n\n" + "Check if the flag(s) are set."; +static PyObject *order_list_is_flag(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + unsigned int flags = 0; + if (PyArg_ParseTuple(args, "O!I", &PyPackage_Type, &pyPkg, + &flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + + return PyBool_FromLong(list->IsFlag(PyPackage_ToCpp(pyPkg), flags)); +} + +static const char order_list_wipe_flags_doc[] = + "wipe_flags(flags: int)\n\n" + "Remove the flags in 'flags' from all packages in this list"; +static PyObject *order_list_wipe_flags(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + unsigned int flags = 0; + if (PyArg_ParseTuple(args, "I", &flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + + list->WipeFlags(flags); + Py_RETURN_NONE; +} + +static const char order_list_is_now_doc[] = + "is_now(pkg: Package)\n\n" + "Check if the package is flagged for any state but removal."; +static PyObject *order_list_is_now(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPkg) == 0) + return 0; + + return PyBool_FromLong(list->IsNow(PyPackage_ToCpp(pyPkg))); +} + +static const char order_list_is_missing_doc[] = + "is_now(pkg: Package)\n\n" + "Check if the package is marked for install."; +static PyObject *order_list_is_missing(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPkg) == 0) + return 0; + + return PyBool_FromLong(list->IsMissing(PyPackage_ToCpp(pyPkg))); +} + + +#define METHOD(name) {#name, order_list_##name, METH_VARARGS,\ + order_list_##name##_doc} + +static PyMethodDef order_list_methods[] = { + METHOD(append), + METHOD(score), + METHOD(order_critical), + METHOD(order_unpack), + METHOD(order_configure), + METHOD(flag), + METHOD(is_flag), + METHOD(is_now), + METHOD(is_missing), + METHOD(wipe_flags), + {} +}; + +static PyObject *order_list_seq_item(PyObject *self,Py_ssize_t index) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *owner = GetOwner<pkgOrderList*>(self); + PyObject *pycache = GetOwner<pkgOrderList*>(owner); + pkgCache *cache = PyCache_ToCpp(pycache); + + if (index < 0 || index >= list->size()) + return PyErr_Format(PyExc_IndexError, "Out of range: %zd", index); + + return PyPackage_FromCpp(pkgCache::PkgIterator(*cache, + *(list->begin() + index)), + true, owner); +} + +Py_ssize_t order_list_seq_length(PyObject *self) +{ + return GetCpp<pkgOrderList*>(self)->size(); +} + +static PySequenceMethods order_list_as_sequence = +{ + order_list_seq_length, // sq_length + 0, // sq_concat + 0, // sq_repeat + order_list_seq_item, // sq_item + 0, // sq_ass_item + 0, // sq_contains + 0, // sq_inplace_concat + 0 // sq_inplace_repeat +}; + +static const char order_list_doc[] = "OrderList(depcache: DepCache)\n\n" + "Sequence type for packages with special ordering methods."; +PyTypeObject PyOrderList_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.OrderList", // tp_name + sizeof(CppPyObject<pkgOrderList*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgOrderList*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &order_list_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 + order_list_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + order_list_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 + order_list_new, // tp_new +}; diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc new file mode 100644 index 0000000..2fb8e71 --- /dev/null +++ b/python/pkgmanager.cc @@ -0,0 +1,375 @@ +// Description /*{{{*/ +// $Id: acquire.cc,v 1.1 2003/06/03 03:03:23 mvo Exp $ +/* ###################################################################### + + PkgManager - Wrapper for the pkgPackageManager code + + ##################################################################### */ + +#include "generic.h" +#include "apt_pkgmodule.h" +#include "pkgrecords.h" + +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/error.h> +#include <apt-pkg/acquire.h> +#include <apt-pkg/init.h> +#include <apt-pkg/install-progress.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/dpkgpm.h> + +#include <iostream> + +static PyObject *PkgManagerGetArchives(PyObject *Self,PyObject *Args) +{ + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + PyObject *fetcher, *list, *recs; + + if (PyArg_ParseTuple(Args, "O!O!O!", + &PyAcquire_Type,&fetcher, + &PySourceList_Type, &list, + &PyPackageRecords_Type, &recs) == 0) + return 0; + + pkgAcquire *s_fetcher = GetCpp<pkgAcquire*>(fetcher); + pkgSourceList *s_list = GetCpp<pkgSourceList*>(list); + PkgRecordsStruct &s_records = GetCpp<PkgRecordsStruct>(recs); + + bool res = pm->GetArchives(s_fetcher, s_list, + &s_records.Records); + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyObject *PkgManagerDoInstall(PyObject *Self,PyObject *Args) +{ + //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + int status_fd = -1; + + if (PyArg_ParseTuple(Args, "|i", &status_fd) == 0) + return 0; + + APT::Progress::PackageManagerProgressFd progress(status_fd); + + pkgPackageManager::OrderResult res = pm->DoInstall(&progress); + + return HandleErrors(MkPyNumber(res)); +} + +static PyObject *PkgManagerFixMissing(PyObject *Self,PyObject *Args) +{ + //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + + if (PyArg_ParseTuple(Args, "") == 0) + return 0; + + bool res = pm->FixMissing(); + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyMethodDef PkgManagerMethods[] = +{ + {"get_archives",PkgManagerGetArchives,METH_VARARGS, + "get_archives(fetcher: Acquire, list: SourceList, recs: PackageRecords) -> bool\n\n" + "Download the packages marked for installation via the Acquire object\n" + "'fetcher', using the information found in 'list' and 'recs'."}, + {"do_install",PkgManagerDoInstall,METH_VARARGS, + "do_install(status_fd: int) -> int\n\n" + "Install the packages and return one of the class constants\n" + "RESULT_COMPLETED, RESULT_FAILED, RESULT_INCOMPLETE. The argument\n" + "status_fd can be used to specify a file descriptor that APT will\n" + "write status information on (see README.progress-reporting in the\n" + "apt source code for information on what will be written there)."}, + {"fix_missing",PkgManagerFixMissing,METH_VARARGS, + "fix_missing() -> bool\n\n" + "Fix the installation if a package could not be downloaded."}, + {} +}; + +static const char *packagemanager_doc = + "_PackageManager objects allow the fetching of packages marked for\n" + "installation and the installation of those packages.\n" + "This is an abstract base class that cannot be subclassed\n" + "in Python. The only subclass is apt_pkg.PackageManager. This\n" + "class is an implementation-detail and not part of the API."; +PyTypeObject PyPackageManager_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg._PackageManager", // tp_name + sizeof(CppPyObject<pkgPackageManager*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgPackageManager*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flag, + packagemanager_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgManagerMethods, // 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 + 0, // tp_new +}; + + +struct CppPyRef { + PyObject *o; + CppPyRef(const CppPyRef &o) { Py_XINCREF(o); this->o = o; } + CppPyRef(PyObject *o) : o(o) {} + ~CppPyRef() { Py_XDECREF(o); } + operator PyObject *() const { return o; } + PyObject *operator->() const { return o; } +}; + +class PyPkgManager : public pkgDPkgPM { + bool res(CppPyRef result, const char* funcname) { + if (result == NULL) { + std::cerr << "Error in function: " << funcname << std::endl; + PyErr_Print(); + PyErr_Clear(); + return false; + } + return (result != NULL && + (result == Py_None || PyObject_IsTrue(result) == 1)); + } + + + PyObject *GetPyPkg(const PkgIterator &Pkg) { + PyObject *depcache = NULL; + PyObject *cache = NULL; + + depcache = GetOwner<PyPkgManager*>(pyinst); + if (depcache != NULL && PyDepCache_Check(depcache)) + cache = GetOwner<pkgDepCache*>(depcache); + + return PyPackage_FromCpp(Pkg, true, cache); + } + + /* Call through to Python */ + virtual bool Install(PkgIterator Pkg,std::string File) { + return res(PyObject_CallMethod(pyinst, "install", "(NN)", + GetPyPkg(Pkg), + CppPyString(File)), + "install"); + } + virtual bool Configure(PkgIterator Pkg) { + return res(PyObject_CallMethod(pyinst, "configure", "(N)", + GetPyPkg(Pkg)), + "configure"); + } + virtual bool Remove(PkgIterator Pkg,bool Purge = false) { + return res(PyObject_CallMethod(pyinst, "remove", "(NN)", + GetPyPkg(Pkg), + PyBool_FromLong(Purge)), + "remove" + ); + } + virtual bool Go(int StatusFd=-1) { + return res(PyObject_CallMethod(pyinst, "go", "(i)", + StatusFd), + "go"); + } + virtual void Reset() { + Py_XDECREF(PyObject_CallMethod(pyinst, "reset", NULL)); + } + +public: + /* Those call the protected functions from the parent class */ + bool callInstall(PkgIterator Pkg,std::string File) { return pkgDPkgPM::Install(Pkg, File); } + bool callRemove(PkgIterator Pkg, bool Purge) { return pkgDPkgPM::Remove(Pkg, Purge); } + bool callGo(int StatusFd=-1) { + APT::Progress::PackageManagerProgressFd progress(StatusFd); + return pkgDPkgPM::Go(&progress); + } + void callReset() { return pkgDPkgPM::Reset(); } + bool callConfigure(PkgIterator Pkg) { return pkgDPkgPM::Configure(Pkg); } + pkgOrderList *getOrderList() { return pkgPackageManager::List; } + + PyPkgManager(pkgDepCache *Cache) : pkgDPkgPM(Cache),pyinst(NULL) {}; + PyObject *pyinst; +}; + +static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"depcache",0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, + &Owner) == 0) + return 0; + + PyPkgManager *pm = new PyPkgManager(GetCpp<pkgDepCache*>(Owner)); + + CppPyObject<PyPkgManager*> *PkgManagerObj = + CppPyObject_NEW<PyPkgManager*>(NULL, type,pm); + + pm->pyinst = PkgManagerObj; + + return PkgManagerObj; +} + + +static PyObject *PkgManagerInstall(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + PyApt_Filename file; + + if (PyArg_ParseTuple(Args, "O!O&", &PyPackage_Type,&pkg, PyApt_Filename::Converter, &file) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callInstall(PyPackage_ToCpp(pkg), file))); +} + + +static PyObject *PkgManagerConfigure(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + + if (PyArg_ParseTuple(Args, "O!", &PyPackage_Type,&pkg) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callConfigure(PyPackage_ToCpp(pkg)))); +} + +static PyObject *PkgManagerRemove(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + char purge; + + if (PyArg_ParseTuple(Args, "O!b", &PyPackage_Type,&pkg, &purge) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callRemove(PyPackage_ToCpp(pkg), purge))); +} + +static PyObject *PkgManagerGo(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + int fd; + + if (PyArg_ParseTuple(Args, "i", &fd) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callGo(fd))); +} + +static PyObject *PkgManagerReset(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + + pm->callReset(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyMethodDef PkgManager2Methods[] = +{ + {"install",PkgManagerInstall,METH_VARARGS, + "install(pkg: Package, filename: str) -> bool \n\n" + "Add a install action. Can be overridden in subclasses.\n\n" + "New in version 0.8.0."}, + {"configure",PkgManagerConfigure,METH_VARARGS, + "configure(pkg: Package) -> bool \n\n" + "Add a configure action. Can be overridden in subclasses.\n\n" + "New in version 0.8.0."}, + {"remove",PkgManagerRemove,METH_VARARGS, + "remove(pkg: Package, purge: bool) -> bool \n\n" + "Add a removal action. Can be overridden in subclasses.\n\n" + "New in version 0.8.0."}, + {"go",PkgManagerGo,METH_VARARGS, + "go(status_fd: int) -> bool \n\n" + "Start dpkg. Can be overridden in subclasses.\n\n" + "New in version 0.8.0."}, + {"reset",PkgManagerReset,METH_VARARGS, + "reset()\n\n" + "Reset the package manager for a new round.\n" + "Can be overridden in subclasses.\n\n" + "New in version 0.8.0."}, + {} +}; + +static const char *packagemanager2_doc = + "PackageManager(depcache: apt_pkg.DepCache)\n\n" + "PackageManager objects allow the fetching of packages marked for\n" + "installation and the installation of those packages. The parameter\n" + "'depcache' specifies an apt_pkg.DepCache object where information\n" + "about the package selections is retrieved from.\n\n" + "Methods in this class can be overridden in sub classes\n" + "to implement behavior different from APT's dpkg implementation."; +PyTypeObject PyPackageManager2_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageManager", // tp_name + sizeof(CppPyObject<PyPkgManager*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<PyPkgManager*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE), + packagemanager2_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgManager2Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyPackageManager_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PkgManagerNew, // tp_new +}; + + + /*}}}*/ diff --git a/python/pkgrecords.cc b/python/pkgrecords.cc new file mode 100644 index 0000000..13c2b9a --- /dev/null +++ b/python/pkgrecords.cc @@ -0,0 +1,280 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgrecords.cc,v 1.3 2002/02/26 01:36:15 mdz Exp $ +/* ###################################################################### + + Package Records - Wrapper for the package records functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" +#include "pkgrecords.h" + + +#include <Python.h> + /*}}}*/ + + +// PkgRecords Class /*{{{*/ +// --------------------------------------------------------------------- + + +static PyObject *PkgRecordsLookup(PyObject *Self,PyObject *Args) +{ + PkgRecordsStruct &Struct = GetCpp<PkgRecordsStruct>(Self); + + PyObject *PkgFObj; + long int Index; + if (PyArg_ParseTuple(Args,"(O!l)",&PyPackageFile_Type,&PkgFObj,&Index) == 0) + return 0; + + // Get the index and check to make sure it is reasonable + pkgCache::PkgFileIterator &PkgF = GetCpp<pkgCache::PkgFileIterator>(PkgFObj); + pkgCache *Cache = PkgF.Cache(); + if (Cache->DataEnd() <= Cache->VerFileP + Index + 1 || + Cache->VerFileP[Index].File != PkgF.MapPointer()) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + + // Do the lookup + Struct.Last = &Struct.Records.Lookup(pkgCache::VerFileIterator(*Cache,Cache->VerFileP+Index)); + + // always return true (to make it consistent with the pkgsrcrecords object + return PyBool_FromLong(1); +} + +static PyMethodDef PkgRecordsMethods[] = +{ + {"lookup",PkgRecordsLookup,METH_VARARGS, + "lookup((packagefile: apt_pkg.PackageFile, index: int)) -> bool\n\n" + "Changes to a new package"}, + {} +}; + +/** + * Get the PkgSrcRecordsStruct from a PyObject. If no package has been looked + * up, set an AttributeError using the given name. + */ +static inline PkgRecordsStruct &GetStruct(PyObject *Self,char *name) { + PkgRecordsStruct &Struct = GetCpp<PkgRecordsStruct>(Self); + if (Struct.Last == 0) + PyErr_SetString(PyExc_AttributeError,name); + return Struct; +} + +static PyObject *PkgRecordsGetFileName(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"FileName"); + return (Struct.Last != 0) ? CppPyPath(Struct.Last->FileName()) : 0; +} +static PyObject *PkgRecordsGetHashes(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"Hashes"); + if (Struct.Last == 0) + return 0; + + auto py = CppPyObject_NEW<HashStringList> (nullptr, &PyHashStringList_Type); + py->Object = Struct.Last->Hashes(); + return py; +} +static PyObject *PkgRecordsGetMD5Hash(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"MD5Hash"); + if (Struct.Last == NULL) + return 0; + auto hashes = Struct.Last->Hashes(); + auto hash = hashes.find("md5sum"); + if (hash == NULL) + return 0; + return CppPyString(hash->HashValue()); +} +static PyObject *PkgRecordsGetSHA1Hash(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"SHA1Hash"); + if (Struct.Last == NULL) + return 0; + auto hashes = Struct.Last->Hashes(); + auto hash = hashes.find("sha1"); + if (hash == NULL) + return 0; + return CppPyString(hash->HashValue()); +} +static PyObject *PkgRecordsGetSHA256Hash(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"SHA256Hash"); + if (Struct.Last == NULL) + return 0; + auto hashes = Struct.Last->Hashes(); + auto hash = hashes.find("sha256"); + if (hash == NULL) + return 0; + return CppPyString(hash->HashValue()); +} +static PyObject *PkgRecordsGetSourcePkg(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"SourcePkg"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->SourcePkg()) : 0; +} +static PyObject *PkgRecordsGetSourceVer(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"SourceVer"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->SourceVer()) : 0; +} +static PyObject *PkgRecordsGetMaintainer(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"Maintainer"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Maintainer()) : 0; +} +static PyObject *PkgRecordsGetShortDesc(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"ShortDesc"); + return (Struct.Last != 0) ? CppPyLocaleString(Struct.Last->ShortDesc()) : 0; +} +static PyObject *PkgRecordsGetLongDesc(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"LongDesc"); + return (Struct.Last != 0) ? CppPyLocaleString(Struct.Last->LongDesc()) : 0; +} +static PyObject *PkgRecordsGetName(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"Name"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Name()) : 0; +} +static PyObject *PkgRecordsGetHomepage(PyObject *Self,void*) { + PkgRecordsStruct &Struct = GetStruct(Self,"Homepage"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Homepage()) : 0; +} +static PyObject *PkgRecordsGetRecord(PyObject *Self,void*) { + const char *start, *stop; + PkgRecordsStruct &Struct = GetStruct(Self,"Record"); + if (Struct.Last == 0) + return 0; + Struct.Last->GetRec(start, stop); + return PyString_FromStringAndSize(start,stop-start); +} +static PyGetSetDef PkgRecordsGetSet[] = { + {"filename",PkgRecordsGetFileName,0, + "The filename of the package, as stored in the 'Filename' field."}, + {"homepage",PkgRecordsGetHomepage,0, + "The homepage of the package, as stored in the 'Homepage' field."}, + {"long_desc",PkgRecordsGetLongDesc,0, + "The long description of the packages; i.e. all lines in the\n" + "'Description' field except for the first one."}, + {"hashes",PkgRecordsGetHashes,0, + "The hashes of the packages, as a HashStringList"}, + {"md5_hash",PkgRecordsGetMD5Hash,0, + "The MD5 hash value of the package, as stored in the 'MD5Sum' field."}, + {"maintainer",PkgRecordsGetMaintainer,0, + "The maintainer of the package, as stored in the 'Maintainer' field."}, + {"name",PkgRecordsGetName,0, + "The name of the package, as stored in the 'Package' field."}, + {"record",PkgRecordsGetRecord,0, + "The raw record, suitable for parsing by apt_pkg.TagSection."}, + {"sha1_hash",PkgRecordsGetSHA1Hash,0, + "The SHA1 hash value, as stored in the 'SHA1' field."}, + {"sha256_hash",PkgRecordsGetSHA256Hash,0, + "The SHA256 hash value, as stored in the 'SHA256' field."}, + {"short_desc",PkgRecordsGetShortDesc,0, + "The short description of the package, i.e. the first line of the\n" + "'Description' field."}, + {"source_pkg",PkgRecordsGetSourcePkg,0, + "The name of the source package, if different from the name of the\n" + "binary package. This information is retrieved from the 'Source' field."}, + {"source_ver",PkgRecordsGetSourceVer,0, + "The version of the source package, if it differs from the version\n" + "of the binary package. Just like 'source_pkg', this information\n" + "is retrieved from the 'Source' field."}, + {} +}; + +static int PkgRecordsContains(PyObject *Self,PyObject *Arg) +{ + PkgRecordsStruct &Struct = GetStruct(Self,"__contains__"); + if (Struct.Last == nullptr) + return -1; + const char *Name = PyObject_AsString(Arg); + + if (Name == nullptr) + return -1; + + return !Struct.Last->RecordField(Name).empty(); +} + +static PyObject *PkgRecordsMap(PyObject *Self,PyObject *Arg) +{ + PkgRecordsStruct &Struct = GetStruct(Self,"__contains__"); + if (Struct.Last == nullptr) + return nullptr; + + const char *Name = PyObject_AsString(Arg); + if (Name == nullptr) + return nullptr; + + return CppPyString(Struct.Last->RecordField(Name)); +} + + + +PySequenceMethods PkgRecordsSeqMeth = {0,0,0,0,0,0,0,PkgRecordsContains,0,0}; +PyMappingMethods PkgRecordsMapMeth = {0,PkgRecordsMap,0}; + +static PyObject *PkgRecordsNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"cache",0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyCache_Type, + &Owner) == 0) + return 0; + + return HandleErrors(CppPyObject_NEW<PkgRecordsStruct>(Owner,type, + GetCpp<pkgCache *>(Owner))); +} + +static const char *packagerecords_doc = + "PackageRecords(cache: apt_pkg.Cache)\n\n" + "Package Records contain information about packages. Those objects\n" + "can be used to retrieve information such as maintainer or filename\n" + "of a package. They can also be used to retrieve the raw records\n" + "of the packages (i.e. those stanzas stored in Packages files)."; + +PyTypeObject PyPackageRecords_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageRecords", // tp_name + sizeof(CppPyObject<PkgRecordsStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<PkgRecordsStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &PkgRecordsSeqMeth, // tp_as_sequence + &PkgRecordsMapMeth, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + packagerecords_doc, // tp_doc + CppTraverse<PkgRecordsStruct>, // tp_traverse + CppClear<PkgRecordsStruct>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgRecordsMethods, // tp_methods + 0, // tp_members + PkgRecordsGetSet, // 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 + PkgRecordsNew, // tp_new +}; + + /*}}}*/ + + diff --git a/python/pkgrecords.h b/python/pkgrecords.h new file mode 100644 index 0000000..1e26c8c --- /dev/null +++ b/python/pkgrecords.h @@ -0,0 +1,10 @@ +#include <apt-pkg/pkgrecords.h> + +struct PkgRecordsStruct +{ + pkgRecords Records; + pkgRecords::Parser *Last; + + PkgRecordsStruct(pkgCache *Cache) : Records(*Cache), Last(0) {}; + PkgRecordsStruct() : Records(*(pkgCache *)0) {abort();}; // G++ Bug.. +}; diff --git a/python/pkgsrcrecords.cc b/python/pkgsrcrecords.cc new file mode 100644 index 0000000..e813c6e --- /dev/null +++ b/python/pkgsrcrecords.cc @@ -0,0 +1,438 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgsrcrecords.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ +/* ###################################################################### + + Package Records - Wrapper for the package records functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/sourcelist.h> + +#include <Python.h> + /*}}}*/ + +// PkgSrcRecordFiles Class /*{{{*/ +// --------------------------------------------------------------------- +typedef pkgSrcRecords::File PkgSrcRecordFilesStruct; + +// compat with the old API that provided a tuple (md5,size,path,type) +static Py_ssize_t pkgSrcRecordFiles_length(PyObject *Self) { + return 4; +} + +// compat with the old API that provided a tuple (md5,size,path,type) +static PyObject* pkgSrcRecordFiles_item(PyObject *Self, Py_ssize_t i) { + APT_IGNORE_DEPRECATED_PUSH + PkgSrcRecordFilesStruct f = GetCpp<PkgSrcRecordFilesStruct>(Self); + switch (i) { + case 0: + Py_INCREF(Py_None); + return Py_None; + case 1: + return Py_BuildValue("N", MkPyNumber(f.FileSize)); + case 2: + return Py_BuildValue("s", f.Path.c_str()); + case 3: + return Py_BuildValue("s", f.Type.c_str()); + } + + PyErr_Format(PyExc_IndexError, "index %d out of range, consider using the properties instead", i); + return NULL; + APT_IGNORE_DEPRECATED_POP +} + +static PySequenceMethods pkgsrcrecordfiles_as_sequence = { + pkgSrcRecordFiles_length,0,0,pkgSrcRecordFiles_item,0,0,0,0,0,0 +}; + +static PyObject *PkgSrcRecordFilesNew(PyTypeObject *type,PyObject *args,PyObject *kwds) { + char *kwlist[] = {0}; + if (PyArg_ParseTupleAndKeywords(args,kwds,"",kwlist) == 0) + return 0; + + return HandleErrors(CppPyObject_NEW<PkgSrcRecordFilesStruct>(NULL, type)); +} + +static const char *sourcerecordfile_doc = + "SourceRecordFile()\n\n" + "Provide an easy way to look up the src records of a source package.\n"; + +static PyObject *PkgSrcRecordFilesGetPath(PyObject *Self,void*) { + PkgSrcRecordFilesStruct f = GetCpp<PkgSrcRecordFilesStruct>(Self); + return CppPyString(f.Path.c_str()); +} + +static PyObject *PkgSrcRecordFilesGetType(PyObject *Self,void*) { + PkgSrcRecordFilesStruct f = GetCpp<PkgSrcRecordFilesStruct>(Self); + return CppPyString(f.Type.c_str()); +} + +static PyObject *PkgSrcRecordFilesGetSize(PyObject *Self,void*) { + PkgSrcRecordFilesStruct f = GetCpp<PkgSrcRecordFilesStruct>(Self); + return Py_BuildValue("N", MkPyNumber(f.FileSize)); +} + +static PyObject *PkgSrcRecordFilesGetHashes(PyObject *Self,void*) { + PkgSrcRecordFilesStruct f = GetCpp<PkgSrcRecordFilesStruct>(Self); + auto py = CppPyObject_NEW<HashStringList> (nullptr, &PyHashStringList_Type); + py->Object = f.Hashes; + return py; +} + +static PyGetSetDef PkgSrcRecordFilesGetSet[] = { + {"path",PkgSrcRecordFilesGetPath,0, + "The remote path of the source package file."}, + {"type",PkgSrcRecordFilesGetType,0, + "The type of the source package file."}, + {"size",PkgSrcRecordFilesGetSize,0, + "The size of the source package file."}, + {"hashes",PkgSrcRecordFilesGetHashes,0, + "The hashes of the source package file."}, + {} +}; + +PyTypeObject PySourceRecordFiles_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.SourceRecordFiles", // tp_name + sizeof(CppPyObject<PkgSrcRecordFilesStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<PkgSrcRecordFilesStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &pkgsrcrecordfiles_as_sequence, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + sourcerecordfile_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + PkgSrcRecordFilesGetSet, // 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 + PkgSrcRecordFilesNew, // tp_new +}; +// --------------------------------------------------------------------- + +struct PkgSrcRecordsStruct +{ + pkgSourceList List; + pkgSrcRecords *Records; + pkgSrcRecords::Parser *Last; + + PkgSrcRecordsStruct() : Last(0) { + List.ReadMainList(); + Records = new pkgSrcRecords(List); + }; + ~PkgSrcRecordsStruct() { + delete Records; + }; +}; + + +// PkgSrcRecords Class /*{{{*/ +// --------------------------------------------------------------------- + +static char *doc_PkgSrcRecordsLookup = + "lookup(name: str) -> bool\n\n" + "Look up the source package with the given name. Each call moves\n" + "the position of the records parser forward. If there are no\n" + "more records, return None. If the lookup failed this way,\n" + "access to any of the attributes will result in an AttributeError."; +static PyObject *PkgSrcRecordsLookup(PyObject *Self,PyObject *Args) +{ + PkgSrcRecordsStruct &Struct = GetCpp<PkgSrcRecordsStruct>(Self); + + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + Struct.Last = Struct.Records->Find(Name, false); + if (Struct.Last == 0) { + Struct.Records->Restart(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } + + return PyBool_FromLong(1); +} + +static char *doc_PkgSrcRecordsRestart = + "restart()\n\n" + "Restart the lookup process. This moves the parser to the first\n" + "package and lookups can now be made just like on a new object."; +static PyObject *PkgSrcRecordsRestart(PyObject *Self,PyObject *Args) +{ + PkgSrcRecordsStruct &Struct = GetCpp<PkgSrcRecordsStruct>(Self); + + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Struct.Records->Restart(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static char *doc_PkgSrcRecordsStep = + "step() -> bool\n\n" + "Go to the source package. Each call moves\n" + "the position of the records parser forward. If there are no\n" + "more records, return None. If the lookup failed this way,\n" + "access to any of the attributes will result in an AttributeError."; +static PyObject *PkgSrcRecordsStep(PyObject *Self,PyObject *Args) +{ + PkgSrcRecordsStruct &Struct = GetCpp<PkgSrcRecordsStruct>(Self); + + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Struct.Last = (pkgSrcRecords::Parser*)Struct.Records->Step(); + if (Struct.Last == 0) { + Struct.Records->Restart(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); + } + + return PyBool_FromLong(1); +} + +static PyMethodDef PkgSrcRecordsMethods[] = +{ + {"lookup",PkgSrcRecordsLookup,METH_VARARGS,doc_PkgSrcRecordsLookup}, + {"restart",PkgSrcRecordsRestart,METH_VARARGS,doc_PkgSrcRecordsRestart}, + {"step",PkgSrcRecordsStep,METH_VARARGS,doc_PkgSrcRecordsStep}, + {} +}; + +/** + * Get the PkgSrcRecordsStruct from a PyObject. If no package has been looked + * up, set an AttributeError using the given name. + */ +static inline PkgSrcRecordsStruct &GetStruct(PyObject *Self,char *name) { + PkgSrcRecordsStruct &Struct = GetCpp<PkgSrcRecordsStruct>(Self); + if (Struct.Last == 0) + PyErr_SetString(PyExc_AttributeError,name); + return Struct; +} + +static PyObject *PkgSrcRecordsGetPackage(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Package"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Package()) : 0; +} +static PyObject *PkgSrcRecordsGetVersion(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Version"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Version()) : 0; +} +static PyObject *PkgSrcRecordsGetMaintainer(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Maintainer"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Maintainer()) : 0; +} +static PyObject *PkgSrcRecordsGetSection(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Section"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->Section()) : 0; +} +static PyObject *PkgSrcRecordsGetRecord(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Record"); + return (Struct.Last != 0) ? CppPyString(Struct.Last->AsStr()) : 0; +} +static PyObject *PkgSrcRecordsGetBinaries(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Binaries"); + if (Struct.Last == 0) + return 0; + PyObject *List = PyList_New(0); + for(const char **b = Struct.Last->Binaries(); *b != 0; ++b) + PyList_Append(List, CppPyString(*b)); + return List; // todo +} +static PyObject *PkgSrcRecordsGetIndex(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Index"); + if (Struct.Last == 0) + return 0; + const pkgIndexFile &tmp = Struct.Last->Index(); + CppPyObject<pkgIndexFile*> *PyObj; + PyObj = CppPyObject_NEW<pkgIndexFile*>(Self,&PyIndexFile_Type, + (pkgIndexFile*)&tmp); + // Do not delete the pkgIndexFile*, it is managed by PkgSrcRecords::Parser. + PyObj->NoDelete=true; + return PyObj; +} + +static PyObject *PkgSrcRecordsGetFiles(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"Files"); + if (Struct.Last == 0) + return 0; + PyObject *List = PyList_New(0); + + std::vector<pkgSrcRecords::File> f; + if(!Struct.Last->Files(f)) + return NULL; // error + + PyObject *v; + for(unsigned int i=0;i<f.size();i++) { + v = CppPyObject_NEW<PkgSrcRecordFilesStruct>(Self, &PySourceRecordFiles_Type, f[i]); + PyList_Append(List, v); + Py_DECREF(v); + } + return List; +} + +static PyObject *PkgSrcRecordsGetBuildDepends(PyObject *Self,void*) { + PkgSrcRecordsStruct &Struct = GetStruct(Self,"BuildDepends"); + if (Struct.Last == 0) + return 0; + + PyObject *Dict = PyDict_New(); + PyObject *Dep = 0; + PyObject *LastDep = 0; + PyObject *OrGroup = 0; + + std::vector<pkgSrcRecords::Parser::BuildDepRec> bd; + if(!Struct.Last->BuildDepends(bd, false /* arch-only*/)) + return NULL; // error + + PyObject *v; + for(unsigned int i=0;i<bd.size();i++) { + + Dep = CppPyString(pkgSrcRecords::Parser::BuildDepType(bd[i].Type)); + + LastDep = PyDict_GetItem(Dict,Dep); + if (LastDep == 0) + { + LastDep = PyList_New(0); + PyDict_SetItem(Dict,Dep,LastDep); + Py_DECREF(LastDep); + } + Py_DECREF(Dep); + OrGroup = PyList_New(0); + PyList_Append(LastDep, OrGroup); + Py_DECREF(OrGroup); + + // Add at least one package to the group, add more if Or is set. + while (i < bd.size()) + { + v = Py_BuildValue("(sss)", bd[i].Package.c_str(), + bd[i].Version.c_str(), pkgCache::CompType(bd[i].Op)); + PyList_Append(OrGroup, v); + Py_DECREF(v); + if (pkgCache::Dep::Or != (bd[i].Op & pkgCache::Dep::Or)) + break; + i++; + } + + } + return Dict; +} + + +static PyGetSetDef PkgSrcRecordsGetSet[] = { + {"binaries",PkgSrcRecordsGetBinaries,0, + "A list of the names of the binaries produced by this source package."}, + {"build_depends",PkgSrcRecordsGetBuildDepends,0, + "A dictionary describing the build-time dependencies of the package;\n" + "the format is the same as used for apt_pkg.Version.depends_list_str."}, + {"files",PkgSrcRecordsGetFiles,0, + "A list of :class:`SourceRecordFiles` objects."}, + {"index",PkgSrcRecordsGetIndex,0, + "The index file associated with this record as a list of\n" + "apt_pkg.IndexFile objects."}, + {"maintainer",PkgSrcRecordsGetMaintainer,0, + "The maintainer of the package."}, + {"package",PkgSrcRecordsGetPackage,0, + "The name of the source package."}, + {"record",PkgSrcRecordsGetRecord,0, + "The raw record, suitable for parsing using apt_pkg.TagSection."}, + {"section",PkgSrcRecordsGetSection,0, + "The section of the source package."}, + {"version",PkgSrcRecordsGetVersion,0, + "The version of the source package."}, + {} +}; + +static PyObject *PkgSrcRecordsNew(PyTypeObject *type,PyObject *args,PyObject *kwds) { + char *kwlist[] = {0}; + if (PyArg_ParseTupleAndKeywords(args,kwds,"",kwlist) == 0) + return 0; + + return HandleErrors(CppPyObject_NEW<PkgSrcRecordsStruct>(NULL, type)); +} + +static const char *sourcerecords_doc = + "SourceRecords()\n\n" + "Provide an easy way to look up the records of source packages and\n" + "provide easy attributes for some widely used fields of the record."; + +PyTypeObject PySourceRecords_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.SourceRecords", // tp_name + sizeof(CppPyObject<PkgSrcRecordsStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<PkgSrcRecordsStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + sourcerecords_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgSrcRecordsMethods, // tp_methods + 0, // tp_members + PkgSrcRecordsGetSet, // 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 + PkgSrcRecordsNew, // tp_new +}; + + + /*}}}*/ + diff --git a/python/policy.cc b/python/policy.cc new file mode 100644 index 0000000..037a530 --- /dev/null +++ b/python/policy.cc @@ -0,0 +1,243 @@ +/* + * policy.cc - Wrapper around pkgPolicy + * + * Copyright 2009 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/policy.h> + +static PyObject *policy_new(PyTypeObject *type,PyObject *Args, + PyObject *kwds) { + PyObject *cache; + char *kwlist[] = {"cache", NULL}; + if (PyArg_ParseTupleAndKeywords(Args, kwds, "O", kwlist, &cache) == 0) + return 0; + if (!PyObject_TypeCheck(cache, &PyCache_Type)) { + PyErr_SetString(PyExc_TypeError,"`cache` must be a apt_pkg.Cache()."); + return 0; + } + pkgPolicy *policy = new pkgPolicy(GetCpp<pkgCache *>(cache)); + return CppPyObject_NEW<pkgPolicy*>(cache,&PyPolicy_Type,policy); +} + +static char *policy_get_priority_doc = + "get_priority(package: Union[apt_pkg.Package, apt_pkg.Version, apt_pkg.PackageFile]) -> int\n\n" + "Return the priority of the package."; + +PyObject *policy_get_priority(PyObject *self, PyObject *arg) { + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + if (PyObject_TypeCheck(arg, &PyVersion_Type)) { + auto ver = GetCpp<pkgCache::VerIterator>(arg); + return MkPyNumber(policy->GetPriority(ver)); + } else if (PyObject_TypeCheck(arg, &PyPackageFile_Type)) { + pkgCache::PkgFileIterator pkgfile = GetCpp<pkgCache::PkgFileIterator>(arg); + return MkPyNumber(policy->GetPriority(pkgfile)); + } else { + PyErr_SetString(PyExc_TypeError,"Argument must be of Version or PackageFile."); + return 0; + } +} + + +static char *policy_set_priority_doc = + "set_priority(which: Union[apt_pkg.Version, apt_pkg.PackageFile], priority: int) -> None\n\n" + "Override priority for the given package/file. Behavior is undefined if" + "a preferences file is read after that, or :meth:`init_defaults` is called."; +static PyObject *policy_set_priority(PyObject *self, PyObject *args) { + PyObject *which; + signed short priority; + if (PyArg_ParseTuple(args, "Oh", &which, &priority) == 0) + return 0; + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + + if (PyObject_TypeCheck(which, &PyVersion_Type)) { + auto ver = GetCpp<pkgCache::VerIterator>(which); + policy->SetPriority(ver, priority); + } else if (PyObject_TypeCheck(which, &PyPackageFile_Type)) { + auto pkgfile = GetCpp<pkgCache::PkgFileIterator>(which); + policy->SetPriority(pkgfile, priority); + } else { + PyErr_SetString(PyExc_TypeError,"Argument must be of Version or PackageFile."); + return 0; + } + + HandleErrors(); + Py_RETURN_NONE; +} + +static char *policy_get_candidate_ver_doc = + "get_match(package: apt_pkg.Package) -> Optional[apt_pkg.Version]\n\n" + "Get the best package for the job."; + +PyObject *policy_get_candidate_ver(PyObject *self, PyObject *arg) { + if (PyObject_TypeCheck(arg, &PyPackage_Type)) { + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + pkgCache::PkgIterator pkg = GetCpp<pkgCache::PkgIterator>(arg); + pkgCache::VerIterator ver = policy->GetCandidateVer(pkg); + if (ver.end()) { + HandleErrors(); + Py_RETURN_NONE; + } + return CppPyObject_NEW<pkgCache::VerIterator>(arg,&PyVersion_Type, + ver); + } else { + PyErr_SetString(PyExc_TypeError,"Argument must be of Package()."); + return 0; + } +} + +static char *policy_read_pinfile_doc = + "read_pinfile(filename: str) -> bool\n\n" + "Read the pin file given by filename (e.g. '/etc/apt/preferences')\n" + "and add it to the policy."; + +static PyObject *policy_read_pinfile(PyObject *self, PyObject *arg) { + PyApt_Filename name; + if (!name.init(arg)) + return 0; + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + + return PyBool_FromLong(ReadPinFile(*policy, name)); +} + +#if (APT_PKG_MAJOR > 4 || (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 8)) +static char *policy_read_pindir_doc = + "read_pindir(dirname: str) -> bool\n\n" + "Read the pin files in the given dir (e.g. '/etc/apt/preferences.d')\n" + "and add them to the policy."; + +static PyObject *policy_read_pindir(PyObject *self, PyObject *arg) { + PyApt_Filename name; + if (!name.init(arg)) + return 0; + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + + return PyBool_FromLong(ReadPinDir(*policy, name)); +} +#endif + +static char *policy_create_pin_doc = + "create_pin(type: str, pkg: str, data: str, priority: int)\n\n" + "Create a pin for the policy. The parameter 'type' refers to one of the\n" + "strings 'Version', 'Release', or 'Origin'. The argument 'pkg' is the\n" + "name of the package. The parameter 'data' refers to the value\n" + "(e.g. 'unstable' for type='Release') and the other possible options.\n" + "The parameter 'priority' gives the priority of the pin."; + +static PyObject *policy_create_pin(PyObject *self, PyObject *args) { + pkgVersionMatch::MatchType match_type; + const char *type, *pkg, *data; + signed short priority; + if (PyArg_ParseTuple(args, "sssh", &type, &pkg, &data, &priority) == 0) + return 0; + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + if (strcmp(type,"Version") == 0 || strcmp(type, "version") == 0) + match_type = pkgVersionMatch::Version; + else if (strcmp(type,"Release") == 0 || strcmp(type, "release") == 0) + match_type = pkgVersionMatch::Release; + else if (strcmp(type,"Origin") == 0 || strcmp(type, "origin") == 0) + match_type = pkgVersionMatch::Origin; + else + match_type = pkgVersionMatch::None; + policy->CreatePin(match_type,pkg,data,priority); + HandleErrors(); + Py_RETURN_NONE; +} + +static char *policy_init_defaults_doc = + "init_defaults()\n\n" + "Initialize defaults. Needed after calling :meth:`create_pin()`\n" + "with an empty `pkg` argument"; +static PyObject *policy_init_defaults(PyObject *self, PyObject *args) { + if (PyArg_ParseTuple(args, "") == 0) + return 0; + pkgPolicy *policy = GetCpp<pkgPolicy *>(self); + policy->InitDefaults(); + HandleErrors(); + Py_RETURN_NONE; +} + +static PyMethodDef policy_methods[] = { + {"get_priority",(PyCFunction)policy_get_priority,METH_O, + policy_get_priority_doc}, + {"set_priority",policy_set_priority,METH_VARARGS,policy_set_priority_doc}, + {"get_candidate_ver",(PyCFunction)policy_get_candidate_ver,METH_O, + policy_get_candidate_ver_doc}, + {"read_pinfile",(PyCFunction)policy_read_pinfile,METH_O, + policy_read_pinfile_doc}, +#if (APT_PKG_MAJOR > 4 || (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 8)) + {"read_pindir",(PyCFunction)policy_read_pindir,METH_O, + policy_read_pindir_doc}, +#endif + {"create_pin",policy_create_pin,METH_VARARGS,policy_create_pin_doc}, + {"init_defaults",policy_init_defaults,METH_VARARGS,policy_init_defaults_doc}, + {} +}; + +static char *policy_doc = + "Policy(cache)\n\n" + "Representation of the policy of the Cache object given by cache. This\n" + "provides a superset of policy-related functionality compared to the\n" + "DepCache class. The DepCache can be used for most purposes, but there\n" + "may be some cases where a special policy class is needed."; + +PyTypeObject PyPolicy_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Policy", // tp_name + sizeof(CppPyObject<pkgPolicy*>),// tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgPolicy*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + policy_doc, // tp_doc + CppTraverse<pkgPolicy*>, // tp_traverse + CppClear<pkgPolicy*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + policy_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 + policy_new, // tp_new +}; diff --git a/python/progress.cc b/python/progress.cc new file mode 100644 index 0000000..f4ed8e6 --- /dev/null +++ b/python/progress.cc @@ -0,0 +1,473 @@ +// Description /*{{{*/ +// $Id: progress.cc,v 1.5 2003/06/03 03:03:23 mvo Exp $ +/* ###################################################################### + + Progress - Wrapper for the progress related functions + + ##################################################################### */ +#include <Python.h> +#include <iostream> +#include <sys/types.h> +#include <sys/wait.h> +#include <map> +#include <utility> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire-worker.h> +#include <apt-pkg/install-progress.h> +#include "progress.h" +#include "generic.h" +#include "apt_pkgmodule.h" + +/** + * Set an attribute on an object, after creating the value with + * Py_BuildValue(fmt, arg). Afterwards, decrease its refcount and return + * whether setting the attribute was successful. + */ +template<class T> +inline bool setattr(PyObject *object, const char *attr, const char *fmt, T arg) +{ + if (!object) + return false; + PyObject *value = Py_BuildValue(fmt, arg); + if (value == NULL) + return false; + + int result = PyObject_SetAttrString(object, attr, value); + Py_DECREF(value); + return result != -1; +} + +inline PyObject *TUPLEIZE(PyObject *op) { + PyObject *ret = Py_BuildValue("(O)", op); + Py_DECREF(op); + return ret; +} + +// generic +bool PyCallbackObj::RunSimpleCallback(const char* method_name, + PyObject *arglist, + PyObject **res) +{ + if(callbackInst == 0) { + Py_XDECREF(arglist); + return false; + } + + PyObject *method = PyObject_GetAttrString(callbackInst,(char*) method_name); + if(method == NULL) { + Py_XDECREF(arglist); + if (res) { + Py_INCREF(Py_None); + *res = Py_None; + } + return false; + } + + PyObject *result = PyObject_CallObject(method, arglist); + Py_XDECREF(arglist); + + if(result == NULL) { + // exception happend + std::cerr << "Error in function " << method_name << std::endl; + PyErr_Print(); + PyErr_Clear(); + + return false; + } + if(res != NULL) + *res = result; + else + Py_XDECREF(result); + Py_XDECREF(method); + + return true; +} + + +// OpProgress interface +void PyOpProgress::Update() +{ + // Build up the argument list... + if(!CheckChange(0.7)) + return; + + setattr(callbackInst, "op", "s", Op.c_str()); + setattr(callbackInst, "subop", "s", SubOp.c_str()); + setattr(callbackInst, "major_change", "b", MajorChange); + setattr(callbackInst, "percent", "N", MkPyNumber(Percent)); + RunSimpleCallback("update"); +} + +void PyOpProgress::Done() +{ + RunSimpleCallback("done"); +} + + + +// fetcher interface + + + +// apt interface + +PyObject *PyFetchProgress::GetDesc(pkgAcquire::ItemDesc *item) { + if (!pyAcquire && item->Owner && item->Owner->GetOwner()) { + pyAcquire = PyAcquire_FromCpp(item->Owner->GetOwner(), false, NULL); + } + PyObject *pyItem = PyAcquireItem_FromCpp(item->Owner, false, pyAcquire); + PyObject *pyDesc = PyAcquireItemDesc_FromCpp(item, false, pyItem); + Py_DECREF(pyItem); + return pyDesc; +} + +bool PyFetchProgress::MediaChange(std::string Media, std::string Drive) +{ + PyCbObj_END_ALLOW_THREADS + PyObject *arglist = Py_BuildValue("(ss)", Media.c_str(), Drive.c_str()); + PyObject *result = NULL; + + if(PyObject_HasAttrString(callbackInst, "mediaChange")) + RunSimpleCallback("mediaChange", arglist, &result); + else + RunSimpleCallback("media_change", arglist, &result); + + bool res = true; + if(!PyArg_Parse(result, "b", &res)) { + // no return value or None, assume false + PyCbObj_BEGIN_ALLOW_THREADS + return false; + } + + PyCbObj_BEGIN_ALLOW_THREADS + return res; +} + +void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status) +{ + // Added object file size and object partial size to + // parameters that are passed to updateStatus. + // -- Stephan + PyObject *arglist = Py_BuildValue("(sssNNN)", Itm.URI.c_str(), + Itm.Description.c_str(), + Itm.ShortDesc.c_str(), + MkPyNumber(status), + MkPyNumber(Itm.Owner->FileSize), + MkPyNumber(Itm.Owner->PartialSize)); + + RunSimpleCallback("update_status_full", arglist); + + // legacy version of the interface + + arglist = Py_BuildValue("(sssN)", Itm.URI.c_str(), Itm.Description.c_str(), + Itm.ShortDesc.c_str(), MkPyNumber(status)); + + if(PyObject_HasAttrString(callbackInst, "updateStatus")) + RunSimpleCallback("updateStatus", arglist); + else + RunSimpleCallback("update_status", arglist); +} + +void PyFetchProgress::IMSHit(pkgAcquire::ItemDesc &Itm) +{ + PyCbObj_END_ALLOW_THREADS + if (PyObject_HasAttrString(callbackInst, "ims_hit")) + RunSimpleCallback("ims_hit", TUPLEIZE(GetDesc(&Itm))); + else + UpdateStatus(Itm, DLHit); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyFetchProgress::Fetch(pkgAcquire::ItemDesc &Itm) +{ + PyCbObj_END_ALLOW_THREADS + if (PyObject_HasAttrString(callbackInst, "fetch")) + RunSimpleCallback("fetch", TUPLEIZE(GetDesc(&Itm))); + else + UpdateStatus(Itm, DLQueued); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyFetchProgress::Done(pkgAcquire::ItemDesc &Itm) +{ + PyCbObj_END_ALLOW_THREADS + if (PyObject_HasAttrString(callbackInst, "done")) + RunSimpleCallback("done", TUPLEIZE(GetDesc(&Itm))); + else + UpdateStatus(Itm, DLDone); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyFetchProgress::Fail(pkgAcquire::ItemDesc &Itm) +{ + PyCbObj_END_ALLOW_THREADS + if (PyObject_HasAttrString(callbackInst, "fail")) { + RunSimpleCallback("fail", TUPLEIZE(GetDesc(&Itm))); + PyCbObj_BEGIN_ALLOW_THREADS + return; + } + + // Ignore certain kinds of transient failures (bad code) + if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) { + PyCbObj_BEGIN_ALLOW_THREADS + return; + } + + if (Itm.Owner->Status == pkgAcquire::Item::StatDone) + { + UpdateStatus(Itm, DLIgnored); + } + + + if (PyObject_HasAttrString(callbackInst, "fail")) + RunSimpleCallback("fail", TUPLEIZE(GetDesc(&Itm))); + else + UpdateStatus(Itm, DLFailed); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyFetchProgress::Start() +{ + pkgAcquireStatus::Start(); + + + RunSimpleCallback("start"); + /* After calling the start method we can safely allow + * other Python threads to do their work for now. + */ + PyCbObj_BEGIN_ALLOW_THREADS +} + + +void PyFetchProgress::Stop() +{ + /* After the stop operation occurred no other threads + * are allowed. This is done so we have a matching + * PyCbObj_END_ALLOW_THREADS to our previous + * PyCbObj_BEGIN_ALLOW_THREADS (Python requires this!). + */ + + PyCbObj_END_ALLOW_THREADS + pkgAcquireStatus::Stop(); + RunSimpleCallback("stop"); +} + +bool PyFetchProgress::Pulse(pkgAcquire * Owner) +{ + PyCbObj_END_ALLOW_THREADS + pkgAcquireStatus::Pulse(Owner); + + if(callbackInst == 0) { + PyCbObj_BEGIN_ALLOW_THREADS + return false; + } + + setattr(callbackInst, "last_bytes", "N", MkPyNumber(LastBytes)); + setattr(callbackInst, "current_cps", "N", MkPyNumber(CurrentCPS)); + setattr(callbackInst, "current_bytes", "N", MkPyNumber(CurrentBytes)); + setattr(callbackInst, "total_bytes", "N", MkPyNumber(TotalBytes)); + setattr(callbackInst, "fetched_bytes", "N", MkPyNumber(FetchedBytes)); + setattr(callbackInst, "elapsed_time", "N", MkPyNumber(ElapsedTime)); + setattr(callbackInst, "current_items", "N", MkPyNumber(CurrentItems)); + setattr(callbackInst, "total_items", "N", MkPyNumber(TotalItems)); + + // New style + if (!PyObject_HasAttrString(callbackInst, "updateStatus")) { + PyObject *result1; + bool res1 = true; + + if (pyAcquire == NULL) { + pyAcquire = PyAcquire_FromCpp(Owner, false, NULL); + } + Py_INCREF(pyAcquire); + + if (RunSimpleCallback("pulse", TUPLEIZE(pyAcquire) , &result1)) { + if (result1 != NULL && + result1 != Py_None && + PyArg_Parse(result1, "b", &res1) && + res1 == false) { + // the user returned a explicit false here, stop + PyCbObj_BEGIN_ALLOW_THREADS + return false; + } + } + PyCbObj_BEGIN_ALLOW_THREADS + return true; + } + return false; +} + + + +// install progress + +void PyInstallProgress::StartUpdate() +{ + RunSimpleCallback("start_update"); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyInstallProgress::UpdateInterface() +{ + PyCbObj_END_ALLOW_THREADS + RunSimpleCallback("update_interface"); + PyCbObj_BEGIN_ALLOW_THREADS +} + +void PyInstallProgress::FinishUpdate() +{ + PyCbObj_END_ALLOW_THREADS + RunSimpleCallback("finish_update"); +} + +pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) +{ + pkgPackageManager::OrderResult res; + int ret; + pid_t child_id; + +#if 0 // FIXME: this needs to be merged into apt to support medium swaping + res = pm->DoInstallPreFork(); + if (res == pkgPackageManager::Failed) + return res; +#endif + + // support custom fork methods + if(PyObject_HasAttrString(callbackInst, "fork")) { + PyObject *method = PyObject_GetAttrString(callbackInst, "fork"); + PyObject *arglist = Py_BuildValue("()"); + PyObject *result = PyObject_CallObject(method, arglist); + Py_DECREF(arglist); + if (result == NULL) { + std::cerr << "fork method invalid" << std::endl; + PyErr_Print(); + return pkgPackageManager::Failed; + } + if(!PyArg_Parse(result, "i", &child_id) ) { + std::cerr << "custom fork() result could not be parsed?"<< std::endl; + return pkgPackageManager::Failed; + } + } else { + child_id = fork(); + } + + PyObject *child_o = MkPyNumber(child_id); + PyObject_SetAttrString(callbackInst, "child_pid", child_o); + Py_DECREF(child_o); + +#if 0 // FIXME: this needs to be merged into apt to support medium swaping + if (child_id == 0) { + res = pm->DoInstallPostFork(); + _exit(res); + } +#endif + if (child_id == 0) { + PyObject *v = PyObject_GetAttrString(callbackInst, "writefd"); + if(v) { + int fd = PyObject_AsFileDescriptor(v); + + APT::Progress::PackageManagerProgressFd progress(fd); + res = pm->DoInstall(&progress); + } else { + APT::Progress::PackageManagerProgressFd progress(-1); + res = pm->DoInstall(&progress); + } + _exit(res); + } + + StartUpdate(); + + + PyCbObj_END_ALLOW_THREADS + if(PyObject_HasAttrString(callbackInst, "waitChild") || + PyObject_HasAttrString(callbackInst, "wait_child")) { + PyObject *method; + if (PyObject_HasAttrString(callbackInst, "waitChild")) + method = PyObject_GetAttrString(callbackInst, "waitChild"); + else + method = PyObject_GetAttrString(callbackInst, "wait_child"); + PyObject *result = PyObject_CallObject(method, NULL); + if (result == NULL) { + std::cerr << "waitChild method invalid" << std::endl; + PyErr_Print(); + PyCbObj_BEGIN_ALLOW_THREADS + return pkgPackageManager::Failed; + } + if(!PyArg_Parse(result, "i", &res) ) { + std::cerr << "custom waitChild() result could not be parsed?"<< std::endl; + PyCbObj_BEGIN_ALLOW_THREADS + return pkgPackageManager::Failed; + } + PyCbObj_BEGIN_ALLOW_THREADS + } else { + PyCbObj_BEGIN_ALLOW_THREADS + while (waitpid(child_id, &ret, WNOHANG) == 0) { + PyCbObj_END_ALLOW_THREADS + UpdateInterface(); + PyCbObj_BEGIN_ALLOW_THREADS + } + + res = (pkgPackageManager::OrderResult) WEXITSTATUS(ret); + } + + FinishUpdate(); + + return res; +} + + +//----------------------------------------------------------------------------- +// apt-cdrom interface + +void PyCdromProgress::Update(std::string text, int current) +{ + PyObject *arglist = Py_BuildValue("(si)", text.c_str(), current); + setattr(callbackInst, "total_steps", "i", totalSteps); + RunSimpleCallback("update", arglist); +} + +bool PyCdromProgress::ChangeCdrom() +{ + PyObject *arglist = Py_BuildValue("()"); + PyObject *result = NULL; + if (PyObject_HasAttrString(callbackInst, "changeCdrom")) + RunSimpleCallback("changeCdrom", arglist, &result); + else + RunSimpleCallback("change_cdrom", arglist, &result); + + bool res = true; + if(!PyArg_Parse(result, "b", &res)) + std::cerr << "ChangeCdrom: result could not be parsed" << std::endl; + + return res; +} + + +bool PyCdromProgress::AskCdromName(std::string &Name) +{ + PyObject *arglist = Py_BuildValue("()"); + const char *new_name; + bool res; + PyObject *result = NULL; + + // Old style: (True, name) on success, (False, name) on failure. + if (PyObject_HasAttrString(callbackInst, "askAdromName")) { + RunSimpleCallback("askAdromName", arglist, &result); + if(!PyArg_Parse(result, "(bs)", &res, &new_name)) + std::cerr << "AskCdromName: result could not be parsed" << std::endl; + // set the new name + Name =std:: string(new_name); + return res; + } + // New style: String on success, None on failure. + else { + RunSimpleCallback("ask_cdrom_name", arglist, &result); + if(result == Py_None) + return false; + if(!PyArg_Parse(result, "s", &new_name)) + std::cerr << "ask_cdrom_name: result could not be parsed" << std::endl; + else + Name = std::string(new_name); + return true; + } +} diff --git a/python/progress.h b/python/progress.h new file mode 100644 index 0000000..b46ac98 --- /dev/null +++ b/python/progress.h @@ -0,0 +1,120 @@ +// Description /*{{{*/ +// $Id: progress.h,v 1.5 2003/06/03 03:03:23 mdz Exp $ +/* ###################################################################### + + Progress - Wrapper for the progress related functions + + ##################################################################### */ + +#ifndef PROGRESS_H +#define PROGRESS_H + +#include <apt-pkg/progress.h> +#include <apt-pkg/acquire.h> +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/cdrom.h> +#include <Python.h> + +/* PyCbObj_BEGIN_ALLOW_THREADS and PyCbObj_END_ALLOW_THREADS are sligthly + * modified versions of Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS. + * Instead of storing the thread state in a function-local variable these + * use a class attribute (with the same) name, allowing blocking and + * unblocking from different class methods. + * Py_BLOCK_THREADS and Py_UNBLOCK_THREADS do not define their own + * local variable but use the one provided by PyCbObj_BEGIN_ALLOW_THREADS + * and thus are the same as Py_BLOCK_THREADS and Py_UNBLOCK_THREADS. + */ +#define PyCbObj_BEGIN_ALLOW_THREADS \ + _save = PyEval_SaveThread(); +#define PyCbObj_END_ALLOW_THREADS \ + PyEval_RestoreThread(_save); \ + _save = NULL; +#define PyCbObj_BLOCK_THREADS Py_BLOCK_THREADS +#define PyCbObj_UNBLOCK_THREADS Py_UNBLOCK_THREADS + +class PyCallbackObj { + protected: + PyObject *callbackInst; + PyThreadState *_save; + + public: + void setCallbackInst(PyObject *o) { + Py_INCREF(o); + callbackInst = o; + } + + bool RunSimpleCallback(const char *method, PyObject *arglist=NULL, + PyObject **result=NULL); + + PyCallbackObj() : callbackInst(0), _save(0) {}; + ~PyCallbackObj() {Py_DECREF(callbackInst); }; +}; + +struct PyOpProgress : public OpProgress, public PyCallbackObj +{ + + virtual void Update(); + virtual void Done(); + + PyOpProgress() : OpProgress(), PyCallbackObj() {}; +}; + + +struct PyFetchProgress : public pkgAcquireStatus, public PyCallbackObj +{ + protected: + PyObject *pyAcquire; + PyObject *GetDesc(pkgAcquire::ItemDesc *item); + public: + enum { + DLDone, DLQueued, DLFailed, DLHit, DLIgnored + }; + + void UpdateStatus(pkgAcquire::ItemDesc & Itm, int status); + + virtual bool MediaChange(std::string Media, std::string Drive); + + void setPyAcquire(PyObject *o) { + Py_CLEAR(pyAcquire); + Py_INCREF(o); + pyAcquire = o; + } + + /* apt stuff */ + virtual void IMSHit(pkgAcquire::ItemDesc &Itm); + virtual void Fetch(pkgAcquire::ItemDesc &Itm); + virtual void Done(pkgAcquire::ItemDesc &Itm); + virtual void Fail(pkgAcquire::ItemDesc &Itm); + virtual void Start(); + virtual void Stop(); + + bool Pulse(pkgAcquire * Owner); + PyFetchProgress() : PyCallbackObj(), pyAcquire(0) {}; + ~PyFetchProgress() { Py_XDECREF(pyAcquire); }; +}; + +struct PyInstallProgress : public PyCallbackObj +{ + void StartUpdate(); + void UpdateInterface(); + void FinishUpdate(); + + pkgPackageManager::OrderResult Run(pkgPackageManager *pm); + + PyInstallProgress() : PyCallbackObj() {}; +}; + +struct PyCdromProgress : public pkgCdromStatus, public PyCallbackObj +{ + // update steps, will be called regularly as a "pulse" + virtual void Update(std::string text="", int current=0); + // ask for cdrom insert + virtual bool ChangeCdrom(); + // ask for cdrom name + virtual bool AskCdromName(std::string &Name); + + PyCdromProgress() : PyCallbackObj() {}; +}; + + +#endif diff --git a/python/python-apt-helpers.cc b/python/python-apt-helpers.cc new file mode 100644 index 0000000..bc58d93 --- /dev/null +++ b/python/python-apt-helpers.cc @@ -0,0 +1,69 @@ +/* + * python-apt.h - Common object creation functions for the public API + * + * Copyright 2010 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 "apt_pkgmodule.h" + +/** + * Short macro to be used for the generic FromCpp functions. + * + */ +#define NEW_FROM(NAME,TYPE,Cpp) \ +PyObject* NAME(Cpp const &obj, bool Delete, PyObject *Owner) \ +{ \ + CppPyObject<Cpp> *Obj = CppPyObject_NEW<Cpp>(Owner, TYPE, obj); \ + Obj->NoDelete = (!Delete); \ + return Obj; \ +} + +// Create all those functions +NEW_FROM(PyAcquireFile_FromCpp,&PyAcquireFile_Type,pkgAcqFile*) +NEW_FROM(PyAcquireItem_FromCpp,&PyAcquireItem_Type,pkgAcquire::Item*) +NEW_FROM(PyAcquireItemDesc_FromCpp,&PyAcquireItemDesc_Type,pkgAcquire::ItemDesc*) +NEW_FROM(PyAcquireWorker_FromCpp,&PyAcquireWorker_Type,pkgAcquire::Worker*) +NEW_FROM(PyActionGroup_FromCpp,&PyActionGroup_Type,pkgDepCache::ActionGroup*) +NEW_FROM(PyCache_FromCpp,&PyCache_Type,pkgCache*) +NEW_FROM(PyCacheFile_FromCpp,&PyCacheFile_Type,pkgCacheFile*) +NEW_FROM(PyCdrom_FromCpp,&PyCdrom_Type,pkgCdrom) +NEW_FROM(PyConfiguration_FromCpp,&PyConfiguration_Type,Configuration*) +NEW_FROM(PyDepCache_FromCpp,&PyDepCache_Type,pkgDepCache*) +NEW_FROM(PyDependency_FromCpp,&PyDependency_Type,pkgCache::DepIterator) +//NEW_FROM(PyDependencyList_FromCpp,&PyDependencyList_Type,RDepListStruct) +NEW_FROM(PyDescription_FromCpp,&PyDescription_Type,pkgCache::DescIterator) +NEW_FROM(PyHashes_FromCpp,&PyHashes_Type,Hashes) +NEW_FROM(PyHashString_FromCpp,&PyHashString_Type,HashString*) +NEW_FROM(PyMetaIndex_FromCpp,&PyMetaIndex_Type,metaIndex*) +NEW_FROM(PyPackage_FromCpp,&PyPackage_Type,pkgCache::PkgIterator) +NEW_FROM(PyGroup_FromCpp,&PyGroup_Type,pkgCache::GrpIterator) +NEW_FROM(PyIndexFile_FromCpp,&PyIndexFile_Type,pkgIndexFile*) +NEW_FROM(PyOrderList_FromCpp,&PyOrderList_Type,pkgOrderList*) +NEW_FROM(PyPackageFile_FromCpp,&PyPackageFile_Type,pkgCache::PkgFileIterator) +//NEW_FROM(PyPackageList_FromCpp,&PyPackageList_Type,PkgListStruct) +NEW_FROM(PyPackageManager_FromCpp,&PyPackageManager_Type,pkgPackageManager*) +//NEW_FROM(PyPackageRecords_FromCpp,&PyPackageRecords_Type,PkgRecordsStruct) +NEW_FROM(PyPolicy_FromCpp,&PyPolicy_Type,pkgPolicy*) +NEW_FROM(PyProblemResolver_FromCpp,&PyProblemResolver_Type,pkgProblemResolver*) +NEW_FROM(PySourceList_FromCpp,&PySourceList_Type,pkgSourceList*) +//NEW_FROM(PySourceRecords_FromCpp,&PySourceRecords_Type,PkgSrcRecordsStruct) +NEW_FROM(PyTagFile_FromCpp,&PyTagFile_Type,pkgTagFile) +NEW_FROM(PyTagSection_FromCpp,&PyTagSection_Type,pkgTagSection) +NEW_FROM(PyVersion_FromCpp,&PyVersion_Type,pkgCache::VerIterator) + +#undef NEW_FROM diff --git a/python/python-apt.h b/python/python-apt.h new file mode 100644 index 0000000..e3c81b0 --- /dev/null +++ b/python/python-apt.h @@ -0,0 +1,368 @@ +/* + * python-apt.h - Header file for the public interface. + * + * Copyright 2009-2010 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. + */ + +#ifndef PYTHON_APT_H +#define PYTHON_APT_H +#include <Python.h> +#include "generic.h" +#include <apt-pkg/configuration.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/version.h> +#include <apt-pkg/deblistparser.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/init.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/cdrom.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/hashes.h> + +typedef PyObject *ActionGroupF(pkgDepCache::ActionGroup *); +typedef pkgDepCache::ActionGroup*& ActionGroupT(PyObject *self); + +struct _PyAptPkgAPIStruct { + // apt_pkg.Acquire (pkgAcquire*) + PyTypeObject *acquire_type; + PyObject* (*acquire_fromcpp)(pkgAcquire *acquire, bool Delete, PyObject*); + pkgAcquire*& (*acquire_tocpp)(PyObject *self); + // apt_pkg.AcquireFile + PyTypeObject *acquirefile_type; + PyObject* (*acquirefile_fromcpp)(pkgAcqFile* const &obj, bool Delete, PyObject *Owner); + pkgAcqFile*& (*acquirefile_tocpp)(PyObject *self); + + // apt_pkg.AcquireItem + PyTypeObject *acquireitem_type; + PyObject* (*acquireitem_fromcpp)(pkgAcquire::Item* const &obj, bool Delete, PyObject *Owner); + pkgAcquire::Item*& (*acquireitem_tocpp)(PyObject *self); + // apt_pkg.AcquireItemDesc + PyTypeObject *acquireitemdesc_type; + PyObject* (*acquireitemdesc_fromcpp)(pkgAcquire::ItemDesc* const &obj, bool Delete, PyObject *Owner); + pkgAcquire::ItemDesc*& (*acquireitemdesc_tocpp)(PyObject *self); + + PyTypeObject *acquireworker_type; + PyObject* (*acquireworker_fromcpp)(pkgAcquire::Worker* const &obj, bool Delete, PyObject *Owner); + pkgAcquire::Worker*& (*acquireworker_tocpp)(PyObject *self); + + PyTypeObject *actiongroup_type; + PyObject* (*actiongroup_fromcpp)(pkgDepCache::ActionGroup* const &obj, bool Delete, PyObject *Owner); + pkgDepCache::ActionGroup*& (*actiongroup_tocpp)(PyObject *self); + + PyTypeObject *cache_type; + PyObject* (*cache_fromcpp)(pkgCache* const &obj, bool Delete, PyObject *Owner); + pkgCache*& (*cache_tocpp)(PyObject *self); + + PyTypeObject *cachefile_type; + PyObject* (*cachefile_fromcpp)(pkgCacheFile* const &obj, bool Delete, PyObject *Owner); + pkgCacheFile*& (*cachefile_tocpp)(PyObject *self); + + PyTypeObject *cdrom_type; + PyObject* (*cdrom_fromcpp)(pkgCdrom const &obj, bool Delete, PyObject *Owner); + pkgCdrom& (*cdrom_tocpp)(PyObject *self); + + PyTypeObject *configuration_type; + PyObject* (*configuration_fromcpp)(Configuration* const &obj, bool Delete, PyObject *Owner); + Configuration*& (*configuration_tocpp)(PyObject *self); + + PyTypeObject *depcache_type; + PyObject* (*depcache_fromcpp)(pkgDepCache* const &obj, bool Delete, PyObject *Owner); + pkgDepCache*& (*depcache_tocpp)(PyObject *self); + + PyTypeObject *dependency_type; + PyObject* (*dependency_fromcpp)(pkgCache::DepIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::DepIterator& (*dependency_tocpp)(PyObject *self); + + PyTypeObject *dependencylist_type; + void *dependencylist_fromcpp; // FIXME: need dependencylist_fromcpp + void *dependencylist_tocpp; // FIXME: need dependencylist_tocpp + + PyTypeObject *description_type; + PyObject* (*description_fromcpp)(pkgCache::DescIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::DescIterator& (*description_tocpp)(PyObject *self); + + PyTypeObject *hashes_type; + PyObject* (*hashes_fromcpp)(Hashes const &obj, bool Delete, PyObject *Owner); + Hashes& (*hashes_tocpp)(PyObject *self); + + PyTypeObject *hashstring_type; + PyObject* (*hashstring_fromcpp)(HashString* const &obj, bool Delete, PyObject *Owner); + HashString*& (*hashstring_tocpp)(PyObject *self); + + PyTypeObject *metaindex_type; + PyObject* (*metaindex_fromcpp)(metaIndex* const &obj, bool Delete, PyObject *Owner); + metaIndex*& (*metaindex_tocpp)(PyObject *self); + + PyTypeObject *package_type; + PyObject* (*package_fromcpp)(pkgCache::PkgIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::PkgIterator& (*package_tocpp)(PyObject *self); + + PyTypeObject *packagefile_type; + PyObject* (*packagefile_fromcpp)(pkgCache::PkgFileIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::PkgFileIterator& (*packagefile_tocpp)(PyObject *self); + + PyTypeObject *packageindexfile_type; + PyObject* (*indexfile_fromcpp)(pkgIndexFile* const &obj, bool Delete, PyObject *Owner); + pkgIndexFile*& (*packageindexfile_tocpp)(PyObject *self); + + PyTypeObject *packagelist_type; + void *packagelist_fromcpp; // FIXME: need packagelist_fromcpp + void *packagelist_tocpp; // FIXME: need packagelist_tocpp + + PyTypeObject *packagemanager_type; + PyObject* (*packagemanager_fromcpp)(pkgPackageManager* const &obj, bool Delete, PyObject *Owner); + pkgPackageManager*& (*packagemanager_tocpp)(PyObject *self); + + PyTypeObject *packagerecords_type; + void *packagerecords_fromcpp; // FIXME: need packagerecords_fromcpp + void *packagerecords_tocpp; // FIXME: need packagerecords_tocpp + + PyTypeObject *policy_type; + PyObject* (*policy_fromcpp)(pkgPolicy* const &obj, bool Delete, PyObject *Owner); + pkgPolicy*& (*policy_tocpp)(PyObject *self); + + PyTypeObject *problemresolver_type; + PyObject* (*problemresolver_fromcpp)(pkgProblemResolver* const &obj, bool Delete, PyObject *Owner); + pkgProblemResolver*& (*problemresolver_tocpp)(PyObject *self); + + PyTypeObject *sourcelist_type; + PyObject* (*sourcelist_fromcpp)(pkgSourceList* const &obj, bool Delete, PyObject *Owner); + pkgSourceList*& (*sourcelist_tocpp)(PyObject *self); + + PyTypeObject *sourcerecords_type; + void *sourcerecords_fromcpp; // FIXME: need sourcerecords_fromcpp + void *sourcerecords_tocpp; // FIXME: need sourcerecords_tocpp + + PyTypeObject *tagfile_type; + PyObject* (*tagfile_fromcpp)(pkgTagFile const &obj, bool Delete, PyObject *Owner); + pkgTagFile& (*tagfile_tocpp)(PyObject *self); + + PyTypeObject *tagsection_type; + PyObject* (*tagsection_fromcpp)(pkgTagSection const &obj, bool Delete, PyObject *Owner); + pkgTagSection& (*tagsection_tocpp)(PyObject *self); + + PyTypeObject *version_type; + PyObject* (*version_fromcpp)(pkgCache::VerIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::VerIterator& (*version_tocpp)(PyObject *self); + + PyTypeObject *group_type; + PyObject* (*group_fromcpp)(pkgCache::GrpIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::GrpIterator& (*group_tocpp)(PyObject *self); + + PyTypeObject *orderlist_type; + PyObject* (*orderlist_fromcpp)(pkgOrderList* const &obj, bool Delete, PyObject *Owner); + pkgOrderList*& (*orderlist_tocpp)(PyObject *self); + + PyTypeObject *sourcerecordfiles_type; + void *sourcerecordfiles_fromcpp; // FIXME: need sourcerecordfiles_fromcpp + void *sourcerecordfiles_tocpp; // FIXME: need sourcerecordfiles_tocpp +}; + +// Checking macros. +# define PyAcquire_Check(op) PyObject_TypeCheck(op, &PyAcquire_Type) +# define PyAcquireFile_Check(op) PyObject_TypeCheck(op, &PyAcquireFile_Type) +# define PyAcquireItem_Check(op) PyObject_TypeCheck(op, &PyAcquireItem_Type) +# define PyAcquireItemDesc_Check(op) PyObject_TypeCheck(op, &PyAcquireItemDesc_Type) +# define PyAcquireWorker_Check(op) PyObject_TypeCheck(op, &PyAcquireWorker_Type) +# define PyActionGroup_Check(op) PyObject_TypeCheck(op, &PyActionGroup_Type) +# define PyCache_Check(op) PyObject_TypeCheck(op, &PyCache_Type) +# define PyCacheFile_Check(op) PyObject_TypeCheck(op, &PyCacheFile_Type) +# define PyCdrom_Check(op) PyObject_TypeCheck(op, &PyCdrom_Type) +# define PyConfiguration_Check(op) PyObject_TypeCheck(op, &PyConfiguration_Type) +# define PyDepCache_Check(op) PyObject_TypeCheck(op, &PyDepCache_Type) +# define PyDependency_Check(op) PyObject_TypeCheck(op, &PyDependency_Type) +# define PyDependencyList_Check(op) PyObject_TypeCheck(op, &PyDependencyList_Type) +# define PyDescription_Check(op) PyObject_TypeCheck(op, &PyDescription_Type) +# define PyGroup_Check(op) PyObject_TypeCheck(op, &PyGroup_Type) +# define PyHashes_Check(op) PyObject_TypeCheck(op, &PyHashes_Type) +# define PyHashString_Check(op) PyObject_TypeCheck(op, &PyHashString_Type) +# define PyIndexRecords_Check(op) PyObject_TypeCheck(op, &PyIndexRecords_Type) +# define PyMetaIndex_Check(op) PyObject_TypeCheck(op, &PyMetaIndex_Type) +# define PyPackage_Check(op) PyObject_TypeCheck(op, &PyPackage_Type) +# define PyPackageFile_Check(op) PyObject_TypeCheck(op, &PyPackageFile_Type) +# define PyIndexFile_Check(op) PyObject_TypeCheck(op, &PyIndexFile_Type) +# define PyPackageList_Check(op) PyObject_TypeCheck(op, &PyPackageList_Type) +# define PyPackageManager_Check(op) PyObject_TypeCheck(op, &PyPackageManager_Type) +# define PyPackageRecords_Check(op) PyObject_TypeCheck(op, &PyPackageRecords_Type) +# define PyPolicy_Check(op) PyObject_TypeCheck(op, &PyPolicy_Type) +# define PyProblemResolver_Check(op) PyObject_TypeCheck(op, &PyProblemResolver_Type) +# define PySourceList_Check(op) PyObject_TypeCheck(op, &PySourceList_Type) +# define PySourceRecords_Check(op) PyObject_TypeCheck(op, &PySourceRecords_Type) +# define PySourceRecordFiles_Check(op) PyObject_TypeCheck(op, &PySourceRecordFiles_Type) +# define PyTagFile_Check(op) PyObject_TypeCheck(op, &PyTagFile_Type) +# define PyTagSection_Check(op) PyObject_TypeCheck(op, &PyTagSection_Type) +# define PyVersion_Check(op) PyObject_TypeCheck(op, &PyVersion_Type) +// Exact check macros. +# define PyAcquire_CheckExact(op) (op->op_type == &PyAcquire_Type) +# define PyAcquireFile_CheckExact(op) (op->op_type == &PyAcquireFile_Type) +# define PyAcquireItem_CheckExact(op) (op->op_type == &PyAcquireItem_Type) +# define PyAcquireItemDesc_CheckExact(op) (op->op_type == &PyAcquireItemDesc_Type) +# define PyAcquireWorker_CheckExact(op) (op->op_type == &PyAcquireWorker_Type) +# define PyActionGroup_CheckExact(op) (op->op_type == &PyActionGroup_Type) +# define PyCache_CheckExact(op) (op->op_type == &PyCache_Type) +# define PyCacheFile_CheckExact(op) (op->op_type == &PyCacheFile_Type) +# define PyCdrom_CheckExact(op) (op->op_type == &PyCdrom_Type) +# define PyConfiguration_CheckExact(op) (op->op_type == &PyConfiguration_Type) +# define PyDepCache_CheckExact(op) (op->op_type == &PyDepCache_Type) +# define PyDependency_CheckExact(op) (op->op_type == &PyDependency_Type) +# define PyDependencyList_CheckExact(op) (op->op_type == &PyDependencyList_Type) +# define PyDescription_CheckExact(op) (op->op_type == &PyDescription_Type) +# define PyHashes_CheckExact(op) (op->op_type == &PyHashes_Type) +# define PyGroup_CheckExact(op) (op->op_type == &PyGroup_Type) +# define PyHashString_CheckExact(op) (op->op_type == &PyHashString_Type) +# define PyIndexRecords_CheckExact(op) (op->op_type == &PyIndexRecords_Type) +# define PyMetaIndex_CheckExact(op) (op->op_type == &PyMetaIndex_Type) +# define PyPackage_CheckExact(op) (op->op_type == &PyPackage_Type) +# define PyPackageFile_CheckExact(op) (op->op_type == &PyPackageFile_Type) +# define PyIndexFile_CheckExact(op) (op->op_type == &PyIndexFile_Type) +# define PyOrderList_CheckExact(op) (op->op_type == &PyOrderList_Type) +# define PyPackageList_CheckExact(op) (op->op_type == &PyPackageList_Type) +# define PyPackageManager_CheckExact(op) (op->op_type == &PyPackageManager_Type) +# define PyPackageRecords_CheckExact(op) (op->op_type == &PyPackageRecords_Type) +# define PyPolicy_CheckExact(op) (op->op_type == &PyPolicy_Type) +# define PyProblemResolver_CheckExact(op) (op->op_type == &PyProblemResolver_Type) +# define PySourceList_CheckExact(op) (op->op_type == &PySourceList_Type) +# define PySourceRecords_CheckExact(op) (op->op_type == &PySourceRecords_Type) +# define PySourceRecordFiles_CheckExact(op) (op->op_type == &PySourceRecordFiles_Type) +# define PyTagFile_CheckExact(op) (op->op_type == &PyTagFile_Type) +# define PyTagSection_CheckExact(op) (op->op_type == &PyTagSection_Type) +# define PyVersion_CheckExact(op) (op->op_type == &PyVersion_Type) + +# ifndef APT_PKGMODULE_H +static struct _PyAptPkgAPIStruct *_PyAptPkg_API; + +static int import_apt_pkg(void) { +# if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1 + _PyAptPkg_API = (_PyAptPkgAPIStruct *)PyCapsule_Import("apt_pkg._C_API", 0); +# else + _PyAptPkg_API = (_PyAptPkgAPIStruct *)PyCObject_Import("apt_pkg", "_C_API"); +# endif // PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1 + return (_PyAptPkg_API != NULL) ? 0 : -1; +} + +# define PyAcquire_Type *(_PyAptPkg_API->acquire_type) +# define PyAcquireFile_Type *(_PyAptPkg_API->acquirefile_type) +# define PyAcquireItem_Type *(_PyAptPkg_API->acquireitem_type) +# define PyAcquireItemDesc_Type *(_PyAptPkg_API->acquireitemdesc_type) +# define PyAcquireWorker_Type *(_PyAptPkg_API->acquireworker_type) +# define PyActionGroup_Type *(_PyAptPkg_API->actiongroup_type) +# define PyCache_Type *(_PyAptPkg_API->cache_type) +# define PyCacheFile_Type *(_PyAptPkg_API->cachefile_type) +# define PyCdrom_Type *(_PyAptPkg_API->cdrom_type) +# define PyConfiguration_Type *(_PyAptPkg_API->configuration_type) +# define PyDepCache_Type *(_PyAptPkg_API->depcache_type) +# define PyDependency_Type *(_PyAptPkg_API->dependency_type) +# define PyDependencyList_Type *(_PyAptPkg_API->dependencylist_type) +# define PyDescription_Type *(_PyAptPkg_API->description_type) +# define PyGroup_Type *(_PyAptPkg_API->group_type) +# define PyHashes_Type *(_PyAptPkg_API->hashes_type) +# define PyHashString_Type *(_PyAptPkg_API->hashstring_type) +# define PyIndexRecords_Type *(_PyAptPkg_API->indexrecords_type) +# define PyMetaIndex_Type *(_PyAptPkg_API->metaindex_type) +# define PyPackage_Type *(_PyAptPkg_API->package_type) +# define PyPackageFile_Type *(_PyAptPkg_API->packagefile_type) +# define PyIndexFile_Type *(_PyAptPkg_API->packageindexfile_type) +# define PyOrderList_Type *(_PyAptPkg_API->orderlist_type) +# define PyPackageList_Type *(_PyAptPkg_API->packagelist_type) +# define PyPackageManager_Type *(_PyAptPkg_API->packagemanager_type) +# define PyPackageRecords_Type *(_PyAptPkg_API->packagerecords_type) +# define PyPolicy_Type *(_PyAptPkg_API->policy_type) +# define PyProblemResolver_Type *(_PyAptPkg_API->problemresolver_type) +# define PySourceList_Type *(_PyAptPkg_API->sourcelist_type) +# define PySourceRecords_Type *(_PyAptPkg_API->sourcerecords_type) +# define PySourceRecordFiles_Type *(_PyAptPkg_API->sourcerecordfiles_type) +# define PyTagFile_Type *(_PyAptPkg_API->tagfile_type) +# define PyTagSection_Type *(_PyAptPkg_API->tagsection_type) +# define PyVersion_Type *(_PyAptPkg_API->version_type) +// Code +# define PyAcquire_ToCpp _PyAptPkg_API->acquire_tocpp +# define PyAcquireFile_ToCpp _PyAptPkg_API->acquirefile_tocpp +# define PyAcquireItem_ToCpp _PyAptPkg_API->acquireitem_tocpp +# define PyAcquireItemDesc_ToCpp _PyAptPkg_API->acquireitemdesc_tocpp +# define PyAcquireWorker_ToCpp _PyAptPkg_API->acquireworker_tocpp +# define PyActionGroup_ToCpp _PyAptPkg_API->actiongroup_tocpp +# define PyCache_ToCpp _PyAptPkg_API->cache_tocpp +# define PyCacheFile_ToCpp _PyAptPkg_API->cachefile_tocpp +# define PyCdrom_ToCpp _PyAptPkg_API->cdrom_tocpp +# define PyConfiguration_ToCpp _PyAptPkg_API->configuration_tocpp +# define PyDepCache_ToCpp _PyAptPkg_API->depcache_tocpp +# define PyDependency_ToCpp _PyAptPkg_API->dependency_tocpp +# define PyDependencyList_ToCpp _PyAptPkg_API->dependencylist_tocpp // NULL +# define PyDescription_ToCpp _PyAptPkg_API->description_tocpp +# define PyGroup_ToCpp _PyAptPkg_API->group_tocpp +# define PyHashes_ToCpp _PyAptPkg_API->hashes_tocpp +# define PyHashString_ToCpp _PyAptPkg_API->hashstring_tocpp +# define PyIndexRecords_ToCpp _PyAptPkg_API->indexrecords_tocpp +# define PyMetaIndex_ToCpp _PyAptPkg_API->metaindex_tocpp +# define PyPackage_ToCpp _PyAptPkg_API->package_tocpp +# define PyPackageFile_ToCpp _PyAptPkg_API->packagefile_tocpp +# define PyIndexFile_ToCpp _PyAptPkg_API->packageindexfile_tocpp +# define PyOrderList_ToCpp _PyAptPkg_API->orderlist_tocpp // NULL +# define PyPackageList_ToCpp _PyAptPkg_API->packagelist_tocpp // NULL +# define PyPackageManager_ToCpp _PyAptPkg_API->packagemanager_tocpp +# define PyPackageRecords_ToCpp _PyAptPkg_API->packagerecords_tocpp +# define PyPolicy_ToCpp _PyAptPkg_API->policy_tocpp +# define PyProblemResolver_ToCpp _PyAptPkg_API->problemresolver_tocpp +# define PySourceList_ToCpp _PyAptPkg_API->sourcelist_tocpp +# define PySourceRecords_ToCpp _PyAptPkg_API->sourcerecords_tocpp // NULL +# define PySourceRecordFiles_ToCpp _PyAptPkg_API->sourcerecordfiles_tocpp // NULL +# define PyTagFile_ToCpp _PyAptPkg_API->tagfile_tocpp +# define PyTagSection_ToCpp _PyAptPkg_API->tagsection_tocpp +# define PyVersion_ToCpp _PyAptPkg_API->version_tocpp +// Get the C++ object +# define PyAcquire_FromCpp _PyAptPkg_API->acquire_fromcpp +# define PyAcquireFile_FromCpp _PyAptPkg_API->acquirefile_fromcpp +# define PyAcquireItem_FromCpp _PyAptPkg_API->acquireitem_fromcpp +# define PyAcquireItemDesc_FromCpp _PyAptPkg_API->acquireitemdesc_fromcpp +# define PyAcquireWorker_FromCpp _PyAptPkg_API->acquireworker_fromcpp +# define PyActionGroup_FromCpp _PyAptPkg_API->actiongroup_fromcpp +# define PyCache_FromCpp _PyAptPkg_API->cache_fromcpp +# define PyCacheFile_FromCpp _PyAptPkg_API->cachefile_fromcpp +# define PyCdrom_FromCpp _PyAptPkg_API->cdrom_fromcpp +# define PyConfiguration_FromCpp _PyAptPkg_API->configuration_fromcpp +# define PyDepCache_FromCpp _PyAptPkg_API->depcache_fromcpp +# define PyDependency_FromCpp _PyAptPkg_API->dependency_fromcpp +# define PyDependencyList_FromCpp _PyAptPkg_API->dependencylist_fromcpp // NULL +# define PyDescription_FromCpp _PyAptPkg_API->description_fromcpp +# define PyGroup_FromCpp _PyAptPkg_API->group_fromcpp +# define PyHashes_FromCpp _PyAptPkg_API->hashes_fromcpp +# define PyHashString_FromCpp _PyAptPkg_API->hashstring_fromcpp +# define PyIndexRecords_FromCpp _PyAptPkg_API->indexrecords_fromcpp +# define PyMetaIndex_FromCpp _PyAptPkg_API->metaindex_fromcpp +# define PyPackage_FromCpp _PyAptPkg_API->package_fromcpp +# define PyPackageFile_FromCpp _PyAptPkg_API->packagefile_fromcpp +# define PyIndexFile_FromCpp _PyAptPkg_API->packageindexfile_fromcpp +# define PyOrderList_FromCpp _PyAptPkg_API->orderlist_fromcpp // NULL +# define PyPackageList_FromCpp _PyAptPkg_API->packagelist_fromcpp // NULL +# define PyPackageManager_FromCpp _PyAptPkg_API->packagemanager_fromcpp +# define PyPackageRecords_FromCpp _PyAptPkg_API->packagerecords_fromcpp +# define PyPolicy_FromCpp _PyAptPkg_API->policy_fromcpp +# define PyProblemResolver_FromCpp _PyAptPkg_API->problemresolver_fromcpp +# define PySourceList_FromCpp _PyAptPkg_API->sourcelist_fromcpp +# define PySourceRecords_FromCpp _PyAptPkg_API->sourcerecords_fromcpp // NULL +# define PySourceRecordFiles_FromCpp _PyAptPkg_API->sourcerecordfiles_fromcpp // NULL +# define PyTagFile_FromCpp _PyAptPkg_API->tagfile_fromcpp +# define PyTagSection_FromCpp _PyAptPkg_API->tagsection_fromcpp +# define PyVersion_FromCpp _PyAptPkg_API->version_fromcpp +# endif // APT_PKGMODULE_H + +#endif + diff --git a/python/sourcelist.cc b/python/sourcelist.cc new file mode 100644 index 0000000..3c1d49c --- /dev/null +++ b/python/sourcelist.cc @@ -0,0 +1,170 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: sourcelist.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ +/* ###################################################################### + + SourcesList - Wrapper for the SourcesList functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/sourcelist.h> + +#include <Python.h> + /*}}}*/ + + + +// PkgsourceList Class /*{{{*/ +// --------------------------------------------------------------------- + +static char *doc_PkgSourceListFindIndex = + "find_index(pkgfile: apt_pkg.PackageFile) -> apt_pkg.IndexFile\n\n" + "Return the index file for the given package file, or None if none\n" + "could be found."; +static PyObject *PkgSourceListFindIndex(PyObject *Self,PyObject *Args) +{ + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + PyObject *pyPkgFileIter; + CppPyObject<pkgIndexFile*> *pyPkgIndexFile; + + if (PyArg_ParseTuple(Args, "O!", &PyPackageFile_Type,&pyPkgFileIter) == 0) + return 0; + + pkgCache::PkgFileIterator &i = GetCpp<pkgCache::PkgFileIterator>(pyPkgFileIter); + pkgIndexFile *index; + if(list->FindIndex(i, index)) + { + pyPkgIndexFile = CppPyObject_NEW<pkgIndexFile*>(pyPkgFileIter,&PyIndexFile_Type,index); + // Do not delete the pkgIndexFile*, it is managed by pkgSourceList. + pyPkgIndexFile->NoDelete = true; + return pyPkgIndexFile; + } + + //&PyIndexFile_Type,&pyPkgIndexFile) + + Py_INCREF(Py_None); + return Py_None; +} + +static char *doc_PkgSourceListReadMainList = + "read_main_list() -> bool\n\n" + "Read /etc/apt/sources.list and similar files to populate the list\n" + "of indexes."; +static PyObject *PkgSourceListReadMainList(PyObject *Self,PyObject *Args) +{ + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + bool res = list->ReadMainList(); + + return HandleErrors(PyBool_FromLong(res)); +} + +static char *doc_PkgSourceListGetIndexes = + "get_indexes(acquire: apt_pkg.Acquire[, all: bool=False]) -> bool\n\n" + "Add all indexes (i.e. stuff like Release files, Packages files)\n" + "to the Acquire object 'acquire'. If 'all' is True, all indexes\n" + "will be added, otherwise only changed indexes will be added."; +static PyObject *PkgSourceListGetIndexes(PyObject *Self,PyObject *Args) +{ + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + + PyObject *pyFetcher; + char all = 0; + if (PyArg_ParseTuple(Args, "O!|b",&PyAcquire_Type,&pyFetcher, &all) == 0) + return 0; + + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(pyFetcher); + bool res = list->GetIndexes(fetcher, all); + + return HandleErrors(PyBool_FromLong(res)); +} + +static PyMethodDef PkgSourceListMethods[] = +{ + {"find_index",PkgSourceListFindIndex,METH_VARARGS,doc_PkgSourceListFindIndex}, + {"read_main_list",PkgSourceListReadMainList,METH_VARARGS,doc_PkgSourceListReadMainList}, + {"get_indexes",PkgSourceListGetIndexes,METH_VARARGS,doc_PkgSourceListGetIndexes}, + {} +}; + +static PyObject *PkgSourceListGetList(PyObject *Self,void*) +{ + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + PyObject *List = PyList_New(0); + for (std::vector<metaIndex *>::const_iterator I = list->begin(); + I != list->end(); I++) + { + CppPyObject<metaIndex*> *Obj; + Obj = CppPyObject_NEW<metaIndex*>(Self, &PyMetaIndex_Type,*I); + // Never delete metaIndex*, they are managed by the pkgSourceList. + Obj->NoDelete = true; + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyGetSetDef PkgSourceListGetSet[] = { + {"list",PkgSourceListGetList,0,"A list of MetaIndex() objects.",0}, + {} +}; + +static PyObject *PkgSourceListNew(PyTypeObject *type,PyObject *args,PyObject *kwds) +{ + char *kwlist[] = {0}; + if (PyArg_ParseTupleAndKeywords(args,kwds,"",kwlist) == 0) + return 0; + return CppPyObject_NEW<pkgSourceList*>(NULL, type,new pkgSourceList()); +} + +static const char *sourcelist_doc = + "SourceList()\n\n" + "Represent the list of sources stored in /etc/apt/sources.list and\n" + "similar files."; +PyTypeObject PySourceList_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.SourceList", // tp_name + sizeof(CppPyObject<pkgSourceList*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgSourceList*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + sourcelist_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgSourceListMethods, // tp_methods + 0, // tp_members + PkgSourceListGetSet, // 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 + PkgSourceListNew, // tp_new +}; + diff --git a/python/string.cc b/python/string.cc new file mode 100644 index 0000000..7cfaa70 --- /dev/null +++ b/python/string.cc @@ -0,0 +1,142 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: string.cc,v 1.3 2002/01/08 06:53:04 jgg Exp $ +/* ###################################################################### + + string - Mappings for the string functions that are worthwile for + Python users + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "apt_pkgmodule.h" +#include "generic.h" + +#include <apt-pkg/strutl.h> + +#include <Python.h> + /*}}}*/ + +// Templated function /*{{{*/ +/* Macro for the generic string in string out function */ +#define MkStr(Python,CFunc) \ +PyObject *Python(PyObject *Self,PyObject *Args) \ +{ \ + char *Str = 0; \ + if (PyArg_ParseTuple(Args,"s",&Str) == 0) \ + return 0; \ + return CppPyString(CFunc(Str)); \ +} + +#define MkInt(Python,CFunc, ctype, pytype, ...) \ +PyObject *Python(PyObject *Self,PyObject *Args) \ +{ \ + ctype Val = 0; \ + if (PyArg_ParseTuple(Args,pytype,&Val) == 0) \ + return 0; \ + return CppPyString(CFunc(Val, ##__VA_ARGS__)); \ +} + +MkStr(StrDeQuote,DeQuoteString); + +/* + * Input bytes(Py3k)/str(Py2), output str. + */ +PyObject *StrBase64Encode(PyObject *Self,PyObject *Args) { + char *Str = 0; + #if PY_MAJOR_VERSION >= 3 + if (PyArg_ParseTuple(Args,"y",&Str) == 0) + #else + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + #endif + return 0; + return CppPyString(Base64Encode(Str)); +} + +PyObject *StrURItoFileName(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + return 0; + return CppPyPath(URItoFileName(Str)); +} + +//MkFloat(StrSizeToStr,SizeToStr); +MkInt(StrTimeToStr,TimeToStr, unsigned long, "k"); +MkInt(StrTimeRFC1123,TimeRFC1123, long long, "L", false); + /*}}}*/ + +// Other String functions /*{{{*/ +PyObject *StrSizeToStr(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + double value; + + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + // In Python 3, PyInt_Check is aliased to PyLong_Check and PyInt_AsLong is + // aliased to PyLong_AsLong. Therefore we do the actual long checks first + // so that if it is a long in Python 3, the value will be converted to a + // double rather than a long. This avoids OverflowError regressions in + // Python 3. LP: #1030278 + if (PyLong_Check(Obj)) + value = PyLong_AsDouble(Obj); + else if (PyInt_Check(Obj)) + value = PyInt_AsLong(Obj); + else if (PyFloat_Check(Obj)) + value = PyFloat_AsDouble(Obj); + else { + PyErr_SetString(PyExc_TypeError,"Only understand integers and floats"); + return 0; + } + // Check for OverflowErrors or other exceptions during conversion. + if (PyErr_Occurred()) + return 0; + return CppPyString(SizeToStr(value)); +} + +PyObject *StrQuoteString(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + char *Bad = 0; + if (PyArg_ParseTuple(Args,"ss",&Str,&Bad) == 0) + return 0; + return CppPyString(QuoteString(Str,Bad)); +} + +PyObject *StrStringToBool(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + return 0; + return MkPyNumber(StringToBool(Str)); +} + +PyObject *StrStrToTime(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + return 0; + + time_t Result; +APT_IGNORE_DEPRECATED_PUSH + if (RFC1123StrToTime(Str,Result) == false) + { +APT_IGNORE_DEPRECATED_POP + Py_INCREF(Py_None); + return Py_None; + } + + return MkPyNumber(Result); +} + +PyObject *StrCheckDomainList(PyObject *Self,PyObject *Args) +{ + char *Host = 0; + char *List = 0; + if (PyArg_ParseTuple(Args,"ss",&Host,&List) == 0) + return 0; + return PyBool_FromLong(CheckDomainList(Host,List)); +} + + /*}}}*/ diff --git a/python/tag.cc b/python/tag.cc new file mode 100644 index 0000000..691b67f --- /dev/null +++ b/python/tag.cc @@ -0,0 +1,1063 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: tag.cc,v 1.3 2002/02/26 01:36:15 mdz Exp $ +/* ###################################################################### + + Tag - Binding for the RFC 822 tag file parser + + Upon reflection I have make the TagSection wrapper look like a map.. + The other option was to use a sequence (which nicely matches the internal + storage) but really makes no sense to a Python Programmer.. One + specialized lookup is provided, the FindFlag lookup - as well as the + usual set of duplicate things to match the C++ interface. + + The TagFile interface is also slightly different, it has a built in + internal TagSection object that is used. Do not hold onto a reference + to a TagSection and let TagFile go out of scope! The underlying storage + for the section will go away and it will seg. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/tagfile.h> +#include <apt-pkg/fileutl.h> + +#include <stdio.h> +#include <iostream> +#include <Python.h> + +using namespace std; + /*}}}*/ +/* We need to keep a private copy of the data.. */ +struct TagSecData : public CppPyObject<pkgTagSection> +{ + char *Data; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif +}; + +// The owner of the TagFile is a Python file object. +struct TagFileData : public CppPyObject<pkgTagFile> +{ + TagSecData *Section; + FileFd Fd; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif +}; + +// Traversal and Clean for owned objects +int TagFileTraverse(PyObject *self, visitproc visit, void* arg) { + Py_VISIT(((TagFileData *)self)->Section); + Py_VISIT(((TagFileData *)self)->Owner); + return 0; +} + +int TagFileClear(PyObject *self) { + Py_CLEAR(((TagFileData *)self)->Section); + Py_CLEAR(((TagFileData *)self)->Owner); + return 0; +} + +// Helpers to return Unicode or bytes as appropriate. +#if PY_MAJOR_VERSION < 3 +#define TagSecString_FromStringAndSize(self, v, len) \ + PyString_FromStringAndSize((v), (len)) +#define TagSecString_FromString(self, v) CppPyString(v) +#else +static PyObject *TagSecString_FromStringAndSize(PyObject *self, const char *v, + Py_ssize_t len) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromStringAndSize(v, len); + else if (Self->Encoding) + return PyUnicode_Decode(v, len, PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromStringAndSize(v, len); +} + +static PyObject *TagSecString_FromString(PyObject *self, const char *v) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromString(v); + else if (Self->Encoding) + return PyUnicode_Decode(v, strlen(v), + PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromString(v); +} +#endif + + + /*}}}*/ +// TagSecFree - Free a Tag Section /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void TagSecFree(PyObject *Obj) +{ + TagSecData *Self = (TagSecData *)Obj; + delete [] Self->Data; + CppDealloc<pkgTagSection>(Obj); +} + /*}}}*/ +// TagFileFree - Free a Tag File /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void TagFileFree(PyObject *Obj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << Obj->ob_type->tp_name << "^ ===\n"; + #endif + PyObject_GC_UnTrack(Obj); + TagFileData *Self = (TagFileData *)Obj; + Py_CLEAR(Self->Section); + Self->Object.~pkgTagFile(); + Self->Fd.~FileFd(); + Py_CLEAR(Self->Owner); + Obj->ob_type->tp_free(Obj); +} + /*}}}*/ + +// Tag Section Wrappers /*{{{*/ +static char *doc_Find = + "find(name: str[, default = None]) -> str\n\n" + "Find the key given by 'name' and return the value. If the key can\n" + "not be found, return 'default'."; +static PyObject *TagSecFind(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|z",&Name,&Default) == 0) + return 0; + + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + { + if (Default == 0) + Py_RETURN_NONE; + return TagSecString_FromString(Self,Default); + } + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +static char *doc_FindRaw = + "find_raw(name: str[, default = None] -> str\n\n" + "Same as find(), but returns the complete 'key: value' field; instead of\n" + "just the value."; +static PyObject *TagSecFindRaw(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|z",&Name,&Default) == 0) + return 0; + + unsigned Pos; + if (GetCpp<pkgTagSection>(Self).Find(Name,Pos) == false) + { + if (Default == 0) + Py_RETURN_NONE; + return TagSecString_FromString(Self,Default); + } + + const char *Start; + const char *Stop; + GetCpp<pkgTagSection>(Self).Get(Start,Stop,Pos); + + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +static char *doc_FindFlag = + "find_flag(name: str) -> int\n\n" + "Return 1 if the key's value is 'yes' or a similar value describing\n" + "a boolean true. If the field does not exist, or does not have such a\n" + "value, return 0."; +static PyObject *TagSecFindFlag(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + unsigned long Flag = 0; + if (GetCpp<pkgTagSection>(Self).FindFlag(Name,Flag,1) == false) + { + Py_INCREF(Py_None); + return Py_None; + } + return PyBool_FromLong(Flag); +} + +static char *doc_Write = + "write(file: int, order: List[str], rewrite: List[Tag]) -> None\n\n" + "Rewrites the section into the given file descriptor, which should be\n" + "a file descriptor or an object providing a fileno() method.\n" + "\n" + ".. versionadded:: 1.9.0"; +static PyObject *TagSecWrite(PyObject *Self, PyObject *Args, PyObject *kwds) +{ + char *kwlist[] = {"file", "order", "rewrite", nullptr}; + PyObject *pFile; + PyObject *pOrder; + PyObject *pRewrite; + if (PyArg_ParseTupleAndKeywords(Args,kwds, "OO!O!",kwlist, &pFile,&PyList_Type,&pOrder, &PyList_Type, &pRewrite) == 0) + return nullptr; + + int fileno = PyObject_AsFileDescriptor(pFile); + // handle invalid arguments + if (fileno == -1) + { + PyErr_SetString(PyExc_TypeError, + "Argument must be string, fd or have a fileno() method"); + return 0; + } + + FileFd file(fileno); + const char **order = ListToCharChar(pOrder,true); + if (order == nullptr) + return nullptr; + std::vector<pkgTagSection::Tag> rewrite; + for (int I = 0; I != PySequence_Length(pRewrite); I++) { + PyObject *item = PySequence_GetItem(pRewrite, I); + if (!PyObject_TypeCheck(item, &PyTag_Type)) + return PyErr_SetString(PyExc_TypeError, "Wrong type for tag in list"), nullptr; + rewrite.push_back(GetCpp<pkgTagSection::Tag>(item)); + } + + return HandleErrors(PyBool_FromLong(GetCpp<pkgTagSection>(Self).Write(file, order, rewrite))); +} + + +// Map access, operator [] +static PyObject *TagSecMap(PyObject *Self,PyObject *Arg) +{ + const char *Name = PyObject_AsString(Arg); + if (Name == 0) + return 0; + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + { + PyErr_SetString(PyExc_KeyError,Name); + return 0; + } + + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +// len() operation +static Py_ssize_t TagSecLength(PyObject *Self) +{ + pkgTagSection &Sec = GetCpp<pkgTagSection>(Self); + return Sec.Count(); +} + +// Look like a mapping +static char *doc_Keys = + "keys() -> list\n\n" + "Return a list of all keys."; +static PyObject *TagSecKeys(PyObject *Self,PyObject *Args) +{ + pkgTagSection &Tags = GetCpp<pkgTagSection>(Self); + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + for (unsigned int I = 0; I != Tags.Count(); I++) + { + const char *Start; + const char *Stop; + Tags.Get(Start,Stop,I); + const char *End = Start; + for (; End < Stop && *End != ':'; End++); + + PyObject *Obj; + PyList_Append(List,Obj = PyString_FromStringAndSize(Start,End-Start)); + Py_DECREF(Obj); + } + return List; +} + +#if PY_MAJOR_VERSION < 3 +static char *doc_Exists = + "has_key(name: str) -> bool\n\n" + "Return True if the key given by 'name' exists, False otherwise."; +static PyObject *TagSecExists(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + const char *Start; + const char *Stop; + return PyBool_FromLong(GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop)); +} +#endif + +static int TagSecContains(PyObject *Self,PyObject *Arg) +{ + const char *Name = PyObject_AsString(Arg); + if (Name == 0) + return 0; + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + return 0; + return 1; +} + +static char *doc_Bytes = + "bytes() -> int\n\n" + "Return the number of bytes this section is large."; +static PyObject *TagSecBytes(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + return MkPyNumber(GetCpp<pkgTagSection>(Self).size()); +} + +static PyObject *TagSecStr(PyObject *Self) +{ + const char *Start; + const char *Stop; + GetCpp<pkgTagSection>(Self).GetSection(Start,Stop); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + /*}}}*/ +// TagFile Wrappers /*{{{*/ +static char *doc_Step = + "step() -> bool\n\n" + "Step forward in the file"; +static PyObject *TagFileStep(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + TagFileData &Obj = *(TagFileData *)Self; + if (Obj.Object.Step(Obj.Section->Object) == false) + return HandleErrors(PyBool_FromLong(0)); + + return HandleErrors(PyBool_FromLong(1)); +} + +// TagFile Wrappers /*{{{*/ +static PyObject *TagFileNext(PyObject *Self) +{ + TagFileData &Obj = *(TagFileData *)Self; + // Replace the section. + Py_CLEAR(Obj.Section); + Obj.Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); + new (&Obj.Section->Object) pkgTagSection(); + Obj.Section->Owner = Self; + Py_INCREF(Obj.Section->Owner); + Obj.Section->Data = 0; + Obj.Section->Bytes = Obj.Bytes; +#if PY_MAJOR_VERSION >= 3 + // We don't need to incref Encoding as the previous Section object already + // held a reference to it. + Obj.Section->Encoding = Obj.Encoding; +#endif + if (Obj.Object.Step(Obj.Section->Object) == false) + return HandleErrors(NULL); + + // Bug-Debian: http://bugs.debian.org/572596 + // Duplicate the data here and scan the duplicated section data; in order + // to not use any shared storage. + // TODO: Provide an API in apt-pkg to do this; this is really ugly. + + // Fetch old section data + const char *Start; + const char *Stop; + Obj.Section->Object.GetSection(Start,Stop); + // Duplicate the data and + // append a \n because GetSection() will only give us a single \n + // but Scan() needs \n\n to work + Obj.Section->Data = new char[Stop-Start+2]; + + memcpy(Obj.Section->Data, Start, Stop - Start); + Obj.Section->Data[Stop-Start] = '\n'; + Obj.Section->Data[Stop-Start+1] = '\0'; + // Rescan it + if(Obj.Section->Object.Scan(Obj.Section->Data, Stop-Start+2) == false) + return HandleErrors(NULL); + + Py_INCREF(Obj.Section); + return HandleErrors(Obj.Section); +} + +static PyObject *TagFileIter(PyObject *Self) { + Py_INCREF(Self); + return Self; +} + +static char *doc_Offset = + "offset() -> int\n\n" + "Return the current offset."; +static PyObject *TagFileOffset(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + return MkPyNumber(((TagFileData *)Self)->Object.Offset()); + +} + +static char *doc_Jump = + "jump(offset: int) -> bool\n\n" + "Jump to the given offset; return True on success. Note that jumping to\n" + "an offset is not very reliable, and the 'section' attribute may point\n" + "to an unexpected section."; +static PyObject *TagFileJump(PyObject *Self,PyObject *Args) +{ + int Offset; + if (PyArg_ParseTuple(Args,"i",&Offset) == 0) + return 0; + + TagFileData &Obj = *(TagFileData *)Self; + if (Obj.Object.Jump(Obj.Section->Object,Offset) == false) + return HandleErrors(PyBool_FromLong(0)); + + return HandleErrors(PyBool_FromLong(1)); +} + +static char *doc_Close = + "close()\n\n" + "Close the file."; +static PyObject *TagFileClose(PyObject *self, PyObject *args) +{ + if (args != NULL && !PyArg_ParseTuple(args, "")) + return NULL; + + TagFileData &Obj = *(TagFileData *) self; + + Obj.Fd.Close(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *TagFileExit(PyObject *self, PyObject *args) +{ + + PyObject *exc_type = 0; + PyObject *exc_value = 0; + PyObject *traceback = 0; + if (!PyArg_UnpackTuple(args, "__exit__", 3, 3, &exc_type, &exc_value, + &traceback)) { + return 0; + } + + PyObject *res = TagFileClose(self, NULL); + + if (res == NULL) { + // The close failed. If no exception happened within the suite, we + // will raise an error here. Otherwise, we just display the error, so + // Python can handle the original exception instead. + if (exc_type == Py_None) + return NULL; + + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + // Return False, as required by the context manager protocol. + Py_RETURN_FALSE; +} + +static PyObject *TagFileEnter(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + Py_INCREF(self); + + return self; +} + + /*}}}*/ +// ParseSection - Parse a single section from a tag file /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *TagSecNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *Data; + Py_ssize_t Len; + char Bytes = 0; + char *kwlist[] = {"text", "bytes", 0}; + + // this allows reading "byte" types from python3 - but we don't + // make (much) use of it yet + if (PyArg_ParseTupleAndKeywords(Args,kwds,"s#|b",kwlist,&Data,&Len,&Bytes) == 0) + return 0; + if (memchr(Data, 0, Len) != nullptr) { + PyErr_SetString(PyExc_ValueError, "Input contains NUL byte"); + return 0; + } + if (Data[Len] != 0) { + PyErr_SetString(PyExc_ValueError, "Input is not terminated by NUL byte"); + return 0; + } + + // Create the object.. + TagSecData *New = (TagSecData*)type->tp_alloc(type, 0); + new (&New->Object) pkgTagSection(); + New->Data = new char[strlen(Data)+2]; + snprintf(New->Data,strlen(Data)+2,"%s\n",Data); + New->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Encoding = 0; +#endif + + if (New->Object.Scan(New->Data,strlen(New->Data)) == false) + { + cerr << New->Data << endl; + Py_DECREF((PyObject *)New); + PyErr_SetString(PyExc_ValueError,"Unable to parse section data"); + return 0; + } + + New->Object.Trim(); + + return New; +} + + /*}}}*/ +// ParseTagFile - Parse a tagd file /*{{{*/ +// --------------------------------------------------------------------- +/* This constructs the parser state. */ + +static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *File = 0; + char Bytes = 0; + + char *kwlist[] = {"file", "bytes", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O|b",kwlist,&File,&Bytes) == 0) + return 0; + + // check if we got a filename or a file object + int fileno = -1; + PyApt_Filename filename; + if (!filename.init(File)) { + PyErr_Clear(); + fileno = PyObject_AsFileDescriptor(File); + } + + // handle invalid arguments + if (fileno == -1 && filename == NULL) + { + PyErr_SetString(PyExc_TypeError, + "Argument must be string, fd or have a fileno() method"); + return 0; + } + + PyApt_UniqueObject<TagFileData> New((TagFileData*)type->tp_alloc(type, 0)); + if (fileno != -1) + { +#ifdef APT_HAS_GZIP + new (&New->Fd) FileFd(); + New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false); +#else + new (&New->Fd) FileFd(fileno,false); +#endif + } + else + { + // FileFd::Extension got added in this revision +#if (APT_PKG_MAJOR > 4 || (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 12)) + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, FileFd::Extension, false); +#else + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, false); +#endif + } + New->Bytes = Bytes; + New->Owner = File; + Py_INCREF(New->Owner); +#if PY_MAJOR_VERSION >= 3 + if (fileno != -1) { + New->Encoding = PyObject_GetAttr(File, PyUnicode_FromString("encoding")); + if (!New->Encoding) + PyErr_Clear(); + if (New->Encoding && !PyUnicode_Check(New->Encoding)) + New->Encoding = 0; + } else + New->Encoding = 0; + Py_XINCREF(New->Encoding); +#endif + new (&New->Object) pkgTagFile(&New->Fd); + + // Create the section + New->Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); + new (&New->Section->Object) pkgTagSection(); + New->Section->Owner = New.get(); + Py_INCREF(New->Section->Owner); + New->Section->Data = 0; + New->Section->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Section->Encoding = New->Encoding; + Py_XINCREF(New->Section->Encoding); +#endif + + return HandleErrors(New.release()); +} + /*}}}*/ + +// Method table for the Tag Section object +static PyMethodDef TagSecMethods[] = +{ + // Query + {"find",TagSecFind,METH_VARARGS,doc_Find}, + {"find_raw",TagSecFindRaw,METH_VARARGS,doc_FindRaw}, + {"find_flag",TagSecFindFlag,METH_VARARGS,doc_FindFlag}, + {"bytes",TagSecBytes,METH_VARARGS,doc_Bytes}, + {"write",(PyCFunction) TagSecWrite,METH_VARARGS|METH_KEYWORDS,doc_Write}, + + // Python Special + {"keys",TagSecKeys,METH_VARARGS,doc_Keys}, +#if PY_MAJOR_VERSION < 3 + {"has_key",TagSecExists,METH_VARARGS,doc_Exists}, +#endif + {"get",TagSecFind,METH_VARARGS,doc_Find}, + {} +}; + + +PySequenceMethods TagSecSeqMeth = {0,0,0,0,0,0,0,TagSecContains,0,0}; +PyMappingMethods TagSecMapMeth = {TagSecLength,TagSecMap,0}; + + +static char *doc_TagSec = "TagSection(text: str, [bytes: bool = False])\n\n" + "Provide methods to access RFC822-style header sections, like those\n" + "found in debian/control or Packages files.\n\n" + "TagSection() behave like read-only dictionaries and also provide access\n" + "to the functions provided by the C++ class (e.g. find).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagSection to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; +PyTypeObject PyTagSection_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagSection", // tp_name + sizeof(TagSecData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagSecFree, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &TagSecSeqMeth, // tp_as_sequence + &TagSecMapMeth, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + TagSecStr, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_TagSec, // tp_doc + CppTraverse<pkgTagSection>, // tp_traverse + CppClear<pkgTagSection>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + TagSecMethods, // 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 + TagSecNew, // tp_new +}; + +// Method table for the Tag File object +static PyMethodDef TagFileMethods[] = +{ + // Query + {"step",TagFileStep,METH_VARARGS,doc_Step}, + {"offset",TagFileOffset,METH_VARARGS,doc_Offset}, + {"jump",TagFileJump,METH_VARARGS,doc_Jump}, + {"close",TagFileClose,METH_VARARGS,doc_Close}, + {"__enter__",TagFileEnter,METH_VARARGS,"Context manager entry, return self."}, + {"__exit__",TagFileExit,METH_VARARGS,"Context manager exit, calls close."}, + + {} +}; + +// Return the current section. +static PyObject *TagFileGetSection(PyObject *Self,void*) { + PyObject *Obj = ((TagFileData *)Self)->Section; + Py_INCREF(Obj); + return Obj; +} + +static PyGetSetDef TagFileGetSet[] = { + {"section",TagFileGetSection,0, + "The current section, as a TagSection object.",0}, + {} +}; + + +static char *doc_TagFile = "TagFile(file, [bytes: bool = False])\n\n" + "TagFile() objects provide access to debian control files, which consist\n" + "of multiple RFC822-style sections.\n\n" + "To provide access to those sections, TagFile objects provide an iterator\n" + "which yields TagSection objects for each section.\n\n" + "TagFile objects also provide another API which uses a shared TagSection\n" + "object in the 'section' member. The functions step() and jump() can be\n" + "used to navigate within the file; offset() returns the current\n" + "position.\n\n" + "It is important to not mix the use of both APIs, because this can have\n" + "unwanted effects.\n\n" + "The parameter 'file' refers to an object providing a fileno() method or\n" + "a file descriptor (an integer).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagFile to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; + +// Type for a Tag File +PyTypeObject PyTagFile_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagFile", // tp_name + sizeof(TagFileData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagFileFree, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_TagFile, // tp_doc + TagFileTraverse, // tp_traverse + TagFileClear, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + TagFileIter, // tp_iter + TagFileNext, // tp_iternext + TagFileMethods, // tp_methods + 0, // tp_members + TagFileGetSet, // 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 + TagFileNew, // tp_new + +}; + + +// Return the current section. +static PyObject *TagGetAction(PyObject *Self,void*) { + return MkPyNumber(GetCpp<pkgTagSection::Tag>(Self).Action); +} + +static PyObject *TagGetName(PyObject *Self,void*) { + return CppPyString(GetCpp<pkgTagSection::Tag>(Self).Name); +} + +static PyObject *TagGetData(PyObject *Self,void*) { + return CppPyString(GetCpp<pkgTagSection::Tag>(Self).Data); +} + +static PyObject *PyTagRename_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *oldName; + char *newName; + char *kwlist[] = {"old_name", "new_name", 0}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"ss",kwlist, &oldName, &newName) == 0) + return nullptr; + if (oldName[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Old tag name may not be empty."); + return nullptr; + } + if (newName[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "New tag name may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Rename(oldName, newName); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyObject *PyTagRewrite_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *name; + char *data; + char *kwlist[] = {"name", "data", 0}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"ss",kwlist, &name, &data) == 0) + return nullptr; + if (name[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Tag name may not be empty."); + return nullptr; + } + if (data[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "New value may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Rewrite(name, data); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyObject *PyTagRemove_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *name; + char *kwlist[] = {"name", nullptr}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"s",kwlist, &name) == 0) + return nullptr; + if (name[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Tag name may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Remove(name); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyGetSetDef TagGetSet[] = { + {"action",TagGetAction,0, + "The action to perform.",0}, + {"name",TagGetName,0, + "The name of the tag to perform the action on.",0}, + {"data",TagGetData,0, + "The data to write instead (for REWRITE), or the new tag name (RENAME)",0}, + {} +}; + +static char doc_Tag[] = "Tag\n\n" + "Identify actions to be executed on a task\n" + "\n" + "This is used in conjunction with :meth:`TagSection.write` to rewrite\n" + "a tag section into a new one.\n" + "\n" + "This class is abstract, use one of the subclasses:\n" + ":class:`TagRewrite`, :class:`TagRemove`, :class:`TagRename`\n" + "\n" + ".. versionadded:: 1.1"; + +static char doc_TagRewrite[] = "TagRewrite(name: str, data: str)\n\n" + "Change the value of the tag to the string passed in *data*\n" + "\n" + ".. versionadded:: 1.1"; +static char doc_TagRename[] = "TagRename(old_name: str, new_name: str)\n\n" + "Rename the tag *old_name* to *new_name*\n" + "\n" + ".. versionadded:: 1.1"; + +static char doc_TagRemove[] = "TagRemove(name: str)\n\n" + "Remove the tag *name* from the tag section\n" + "\n" + ".. versionadded:: 1.1"; + + +// Type for a Tag File +PyTypeObject PyTag_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Tag", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + | Py_TPFLAGS_BASETYPE), + doc_Tag, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + TagGetSet, // 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 + 0, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRewrite_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRewrite", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + doc_TagRewrite, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRewrite_New, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRemove_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRemove", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + doc_TagRemove, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRemove_New, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRename_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRename", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // 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 + doc_TagRename, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRename_New, // tp_new +}; diff --git a/python/tarfile.cc b/python/tarfile.cc new file mode 100644 index 0000000..b87fa71 --- /dev/null +++ b/python/tarfile.cc @@ -0,0 +1,521 @@ +/* + * arfile.cc - Wrapper around ExtractTar which behaves like Python's tarfile. + * + * Copyright 2009 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 "generic.h" +#include "apt_instmodule.h" +#include <apt-pkg/extracttar.h> +#include <apt-pkg/error.h> +#include <apt-pkg/dirstream.h> + +/** + * A subclass of pkgDirStream which calls a Python callback. + * + * This calls a Python callback in FinishedFile() with the Item as the first + * argument and the data as the second argument. + * + * It can also work without a callback, in which case it just sets the + * 'py_member' and 'py_data' members. This can be combined with setting + * 'member' to extract a single member into the memory. + */ +class PyDirStream : public pkgDirStream +{ + +public: + PyObject *callback; + PyObject *py_data; + // The requested member or NULL. + const char *member; + // Set to true if an error occurred in the Python callback, or a file + // was too large to read in extractdata. + bool error; + // Place where the copy of the data is stored. + char *copy; + // The size of the copy + size_t copy_size; + + virtual bool DoItem(Item &Itm,int &Fd); + virtual bool FinishedFile(Item &Itm,int Fd); +#if (APT_PKG_MAJOR >= 5) + virtual bool Process(Item &Itm,const unsigned char *Data, + unsigned long long Size,unsigned long long Pos); +#else + virtual bool Process(Item &Itm,const unsigned char *Data, + unsigned long Size,unsigned long Pos); +#endif + PyDirStream(PyObject *callback, const char *member=0) : callback(callback), + py_data(0), member(member), error(false), copy(0), copy_size(0) + { + Py_XINCREF(callback); + } + + virtual ~PyDirStream() { + Py_XDECREF(callback); + Py_XDECREF(py_data); + delete[] copy; + } +}; + +bool PyDirStream::DoItem(Item &Itm, int &Fd) +{ + if (!member || strcmp(Itm.Name, member) == 0) { + // Allocate a new buffer if the old one is too small. + if (Itm.Size > SIZE_MAX) + goto to_large; + if (copy == NULL || copy_size < Itm.Size) { + delete[] copy; + copy = new (std::nothrow) char[Itm.Size]; + if (copy == NULL) + goto to_large; + copy_size = Itm.Size; + } + Fd = -2; + } else { + Fd = -1; + } + return true; +to_large: + delete[] copy; + copy = NULL; + copy_size = 0; + /* If we are looking for a specific member, abort reading now */ + if (member) { + error = true; + PyErr_Format(PyExc_MemoryError, + "The member %s was too large to read into memory", + Itm.Name); + return false; + } + return true; +} + +#if (APT_PKG_MAJOR >= 5) +bool PyDirStream::Process(Item &Itm,const unsigned char *Data, + unsigned long long Size,unsigned long long Pos) +#else +bool PyDirStream::Process(Item &Itm,const unsigned char *Data, + unsigned long Size,unsigned long Pos) +#endif +{ + if (copy != NULL) + memcpy(copy + Pos, Data,Size); + return true; +} + +bool PyDirStream::FinishedFile(Item &Itm,int Fd) +{ + if (member && strcmp(Itm.Name, member) != 0) + // Skip non-matching Items, if a specific one is requested. + return true; + + Py_XDECREF(py_data); + if (copy == NULL) { + Py_INCREF(Py_None); + py_data = Py_None; + } else { + py_data = PyBytes_FromStringAndSize(copy, Itm.Size); + } + + if (!callback) + return true; + + // The current member and data. + CppPyObject<Item> *py_member; + py_member = CppPyObject_NEW<Item>(0, &PyTarMember_Type); + // Clone our object, including the strings in it. + py_member->Object = Itm; + py_member->Object.Name = new char[strlen(Itm.Name)+1]; + py_member->Object.LinkTarget = new char[strlen(Itm.LinkTarget)+1]; + strcpy(py_member->Object.Name, Itm.Name); + strcpy(py_member->Object.LinkTarget,Itm.LinkTarget); + py_member->NoDelete = true; + error = PyObject_CallFunctionObjArgs(callback, py_member, py_data, 0) == 0; + // Clear the old objects and create new ones. + Py_XDECREF(py_member); + return (!error); +} + +void tarmember_dealloc(PyObject *self) { + // We cloned those strings, delete them again. + delete[] GetCpp<pkgDirStream::Item>(self).Name; + delete[] GetCpp<pkgDirStream::Item>(self).LinkTarget; + CppDealloc<pkgDirStream::Item>(self); +} + +// The tarfile.TarInfo interface for our TarMember class. +static PyObject *tarmember_isblk(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::BlockDevice); +} +static PyObject *tarmember_ischr(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::CharDevice); +} +static PyObject *tarmember_isdev(PyObject *self, PyObject *args) +{ + pkgDirStream::Item::Type_t type = GetCpp<pkgDirStream::Item>(self).Type; + return PyBool_FromLong(type == pkgDirStream::Item::CharDevice || + type == pkgDirStream::Item::BlockDevice || + type == pkgDirStream::Item::FIFO); +} + +static PyObject *tarmember_isdir(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::Directory); +} + +static PyObject *tarmember_isfifo(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::FIFO); +} + +static PyObject *tarmember_isfile(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::File); +} +static PyObject *tarmember_islnk(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::HardLink); +} +static PyObject *tarmember_isreg(PyObject *self, PyObject *args) +{ + return tarmember_isfile(self, NULL); +} +static PyObject *tarmember_issym(PyObject *self, PyObject *args) +{ + return PyBool_FromLong(GetCpp<pkgDirStream::Item>(self).Type == + pkgDirStream::Item::SymbolicLink); +} + +static PyObject *tarmember_get_name(PyObject *self, void *closure) +{ + return CppPyPath(GetCpp<pkgDirStream::Item>(self).Name); +} + +static PyObject *tarmember_get_linkname(PyObject *self, void *closure) +{ + return CppPyPath(GetCpp<pkgDirStream::Item>(self).LinkTarget); +} + +static PyObject *tarmember_get_mode(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Mode); +} + +static PyObject *tarmember_get_uid(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).UID); +} +static PyObject *tarmember_get_gid(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).GID); +} +static PyObject *tarmember_get_size(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Size); +} + +static PyObject *tarmember_get_mtime(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).MTime); +} + +static PyObject *tarmember_get_major(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Major); +} + +static PyObject *tarmember_get_minor(PyObject *self, void *closure) +{ + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Minor); +} + +static PyObject *tarmember_repr(PyObject *self) +{ + return PyString_FromFormat("<%s object: name:'%s'>", + self->ob_type->tp_name, + GetCpp<pkgDirStream::Item>(self).Name); + +} + + +static PyMethodDef tarmember_methods[] = { + {"isblk",tarmember_isblk,METH_NOARGS, + "Determine whether the member is a block device."}, + {"ischr",tarmember_ischr,METH_NOARGS, + "Determine whether the member is a character device."}, + {"isdev",tarmember_isdev,METH_NOARGS, + "Determine whether the member is a device (block, character or FIFO)."}, + {"isdir",tarmember_isdir,METH_NOARGS, + "Determine whether the member is a directory."}, + {"isfifo",tarmember_isfifo,METH_NOARGS, + "Determine whether the member is a FIFO."}, + {"isfile",tarmember_isfile,METH_NOARGS, + "Determine whether the member is a regular file."}, + {"islnk",tarmember_islnk,METH_NOARGS, + "Determine whether the member is a hardlink."}, + {"isreg",tarmember_isreg,METH_NOARGS, + "Determine whether the member is a regular file, same as isfile()."}, + {"issym",tarmember_issym,METH_NOARGS, + "Determine whether the member is a symbolic link."}, + {NULL} +}; + +static PyGetSetDef tarmember_getset[] = { + {"gid",tarmember_get_gid,0,"The owner's group ID."}, + {"linkname",tarmember_get_linkname,0,"The target of the link."}, + {"major",tarmember_get_major,0,"The major ID of the device."}, + {"minor",tarmember_get_minor,0,"The minor ID of the device."}, + {"mode",tarmember_get_mode,0,"The mode (permissions)."}, + {"mtime",tarmember_get_mtime,0,"Last time of modification."}, + {"name",tarmember_get_name,0,"The name of the file."}, + {"size",tarmember_get_size,0,"The size of the file."}, + {"uid",tarmember_get_uid,0,"The owner's user ID."}, + {NULL} +}; + +static const char *tarmember_doc = + "Represent a single member of a 'tar' archive.\n\n" + "This class, which has been modelled after 'tarfile.TarInfo', represents\n" + "information about a given member in an archive."; +PyTypeObject PyTarMember_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.TarMember", // tp_name + sizeof(CppPyObject<pkgDirStream::Item>), // tp_basicsize + 0, // tp_itemsize + // Methods + tarmember_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + tarmember_repr, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + tarmember_doc, // tp_doc + CppTraverse<pkgDirStream::Item>, // tp_traverse + CppClear<pkgDirStream::Item>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + tarmember_methods, // tp_methods + 0, // tp_members + tarmember_getset // tp_getset +}; + + + +static PyObject *tarfile_new(PyTypeObject *type,PyObject *args,PyObject *kwds) +{ + PyObject *file; + PyApt_Filename filename; + int fileno; + int min = 0; + int max = 0xFFFFFFFF; + char *comp = "gzip"; + + static char *kwlist[] = {"file","min","max","comp",NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O|iis", kwlist, &file, &min, + &max,&comp) == 0) + return 0; + + PyApt_UniqueObject<PyTarFileObject> self((PyTarFileObject*)CppPyObject_NEW<ExtractTar*>(file,type)); + + // We receive a filename. + if (filename.init(file)) + new (&self->Fd) FileFd((const char *) filename,FileFd::ReadOnly); + else if ((fileno = PyObject_AsFileDescriptor(file)) != -1) { + // clear the error set by PyObject_AsString(). + PyErr_Clear(); + new (&self->Fd) FileFd(fileno,false); + } + else { + return 0; + } + + self->min = min; + self->Object = new ExtractTar(self->Fd,max,comp); + if (_error->PendingError() == true) + return HandleErrors(self.release()); + return self.release(); +} + +static const char *tarfile_extractall_doc = + "extractall([rootdir: str]) -> True\n\n" + "Extract the archive in the current directory. The argument 'rootdir'\n" + "can be used to change the target directory."; +static PyObject *tarfile_extractall(PyObject *self, PyObject *args) +{ + std::string cwd = SafeGetCWD(); + PyApt_Filename rootdir; + if (PyArg_ParseTuple(args,"|O&:extractall", PyApt_Filename::Converter, &rootdir) == 0) + return 0; + + if (rootdir) { + if (chdir(rootdir) == -1) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, rootdir); + } + + pkgDirStream Extract; + + ((PyTarFileObject*)self)->Fd.Seek(((PyTarFileObject*)self)->min); + bool res = GetCpp<ExtractTar*>(self)->Go(Extract); + + + + if (rootdir) { + if (chdir(cwd.c_str()) == -1) + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, + (char*)cwd.c_str()); + } + return HandleErrors(PyBool_FromLong(res)); +} + +static const char *tarfile_go_doc = + "go(callback: callable[, member: str]) -> True\n\n" + "Go through the archive and call the callable 'callback' for each\n" + "member with 2 arguments. The first argument is the TarMember and\n" + "the second one is the data, as bytes.\n\n" + "The optional parameter 'member' can be used to specify the member for\n" + "which to call the callback. If not specified, it will be called for all\n" + "members. If specified and not found, LookupError will be raised."; +static PyObject *tarfile_go(PyObject *self, PyObject *args) +{ + PyObject *callback; + PyApt_Filename member; + if (PyArg_ParseTuple(args,"O|O&",&callback, PyApt_Filename::Converter, &member) == 0) + return 0; + if (member && strcmp(member, "") == 0) + member = 0; + pkgDirStream Extract; + PyDirStream stream(callback, member); + ((PyTarFileObject*)self)->Fd.Seek(((PyTarFileObject*)self)->min); + bool res = GetCpp<ExtractTar*>(self)->Go(stream); + if (stream.error) + return 0; + if (member && !stream.py_data) + return PyErr_Format(PyExc_LookupError, "There is no member named '%s'", + member.path); + return HandleErrors(PyBool_FromLong(res)); +} + +static const char *tarfile_extractdata_doc = + "extractdata(member: str) -> bytes\n\n" + "Return the contents of the member, as a bytes object. Raise\n" + "LookupError if there is no member with the given name."; +static PyObject *tarfile_extractdata(PyObject *self, PyObject *args) +{ + PyApt_Filename member; + if (PyArg_ParseTuple(args,"O&", PyApt_Filename::Converter, &member) == 0) + return 0; + PyDirStream stream(NULL, member); + ((PyTarFileObject*)self)->Fd.Seek(((PyTarFileObject*)self)->min); + // Go through the stream. + GetCpp<ExtractTar*>(self)->Go(stream); + + if (stream.error) + return 0; + + if (!stream.py_data) + return PyErr_Format(PyExc_LookupError, "There is no member named '%s'", + member.path); + return Py_INCREF(stream.py_data), stream.py_data; +} + +static PyMethodDef tarfile_methods[] = { + {"extractdata",tarfile_extractdata,METH_VARARGS,tarfile_extractdata_doc}, + {"extractall",tarfile_extractall,METH_VARARGS,tarfile_extractall_doc}, + {"go",tarfile_go,METH_VARARGS,tarfile_go_doc}, + {NULL} +}; + +static PyObject *tarfile_repr(PyObject *self) +{ + return PyString_FromFormat("<%s object: %s>", self->ob_type->tp_name, + PyString_AsString(PyObject_Repr(GetOwner<ExtractTar*>(self)))); +} + +static const char *tarfile_doc = + "TarFile(file: str/int/file[, min: int, max: int, comp: str])\n\n" + "The parameter 'file' may be a string specifying the path of a file, or\n" + "a file-like object providing the fileno() method. It may also be an int\n" + "specifying a file descriptor (returned by e.g. os.open()).\n\n" + "The parameter 'min' describes the offset in the file where the archive\n" + "begins and the parameter 'max' is the size of the archive.\n\n" + "The compression of the archive is set by the parameter 'comp'. It can\n" + "be set to any program supporting the -d switch, the default being gzip."; +PyTypeObject PyTarFile_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_inst.TarFile", // tp_name + sizeof(PyTarFileObject), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<ExtractTar*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + tarfile_repr, // tp_repr + 0, // tp_as_number + 0, // 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 + Py_TPFLAGS_HAVE_GC, + tarfile_doc, // tp_doc + CppTraverse<ExtractTar*>, // tp_traverse + CppClear<ExtractTar*>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + tarfile_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 + tarfile_new // tp_new +}; |