repomd: Refactoring + python fuctions + etc.
authorTomas Mlcoch <tmlcoch@redhat.com>
Mon, 3 Jun 2013 10:33:25 +0000 (12:33 +0200)
committerTomas Mlcoch <tmlcoch@redhat.com>
Mon, 3 Jun 2013 14:14:00 +0000 (16:14 +0200)
23 files changed:
src/createrepo_c.c
src/mergerepo_c.c
src/python/__init__.py
src/python/createrepo_cmodule.c
src/python/load_metadata-py.c
src/python/repomd-py.c
src/python/repomd-py.h
src/python/repomdrecord-py.c
src/python/repomdrecord-py.h
src/python/typeconversion.c
src/python/typeconversion.h
src/python/xml_parser-py.c
src/python/xml_parser-py.h
src/repomd.c
src/repomd.h
src/repomd_internal.h
src/xml_parser.c
src/xml_parser.h
src/xml_parser_repomd.c
tests/python/tests/fixtures.py
tests/python/tests/test_repomd.py
tests/python/tests/test_repomdrecord.py
tests/python/tests/test_xml_parser.py

index 345a367..eaaabac 100644 (file)
@@ -1005,9 +1005,9 @@ main(int argc, char **argv)
 
     cr_Repomd *repomd_obj = cr_repomd_new();
 
-    cr_RepomdRecord *pri_xml_rec = cr_repomd_record_new(pri_xml_filename);
-    cr_RepomdRecord *fil_xml_rec = cr_repomd_record_new(fil_xml_filename);
-    cr_RepomdRecord *oth_xml_rec = cr_repomd_record_new(oth_xml_filename);
+    cr_RepomdRecord *pri_xml_rec = cr_repomd_record_new(pri_xml_filename, "primary");
+    cr_RepomdRecord *fil_xml_rec = cr_repomd_record_new(fil_xml_filename, "filelists");
+    cr_RepomdRecord *oth_xml_rec = cr_repomd_record_new(oth_xml_filename, "other");
     cr_RepomdRecord *pri_db_rec               = NULL;
     cr_RepomdRecord *fil_db_rec               = NULL;
     cr_RepomdRecord *oth_db_rec               = NULL;
@@ -1026,8 +1026,8 @@ main(int argc, char **argv)
     // Groupfile
 
     if (groupfile) {
-        groupfile_rec = cr_repomd_record_new(groupfile);
-        compressed_groupfile_rec = cr_repomd_record_new(groupfile);
+        groupfile_rec = cr_repomd_record_new(groupfile, "group");
+        compressed_groupfile_rec = cr_repomd_record_new(groupfile, "group_gz");
         cr_repomd_record_compress_and_fill(groupfile_rec,
                                           compressed_groupfile_rec,
                                           cmd_options->checksum_type,
@@ -1039,7 +1039,7 @@ main(int argc, char **argv)
     // Updateinfo
 
     if (updateinfo) {
-        updateinfo_rec = cr_repomd_record_new(updateinfo);
+        updateinfo_rec = cr_repomd_record_new(updateinfo, "updateinfo");
         cr_repomd_record_fill(updateinfo_rec, cmd_options->checksum_type, NULL);
     }
 
@@ -1077,9 +1077,9 @@ main(int argc, char **argv)
 
         // Prepare repomd records
 
-        pri_db_rec = cr_repomd_record_new(pri_db_name);
-        fil_db_rec = cr_repomd_record_new(fil_db_name);
-        oth_db_rec = cr_repomd_record_new(oth_db_name);
+        pri_db_rec = cr_repomd_record_new(pri_db_name, "primary_db");
+        fil_db_rec = cr_repomd_record_new(fil_db_name, "filelists_db");
+        oth_db_rec = cr_repomd_record_new(oth_db_name, "other_db");
 
         cr_repomd_record_fill(pri_db_rec, cmd_options->checksum_type, NULL);
         cr_repomd_record_fill(fil_db_rec, cmd_options->checksum_type, NULL);
@@ -1108,15 +1108,15 @@ main(int argc, char **argv)
 
     // Gen xml
 
-    cr_repomd_set_record(repomd_obj, pri_xml_rec,    "primary");
-    cr_repomd_set_record(repomd_obj, fil_xml_rec,    "filelists");
-    cr_repomd_set_record(repomd_obj, oth_xml_rec,    "other");
-    cr_repomd_set_record(repomd_obj, pri_db_rec,     "primary_db");
-    cr_repomd_set_record(repomd_obj, fil_db_rec,     "filelists_db");
-    cr_repomd_set_record(repomd_obj, oth_db_rec,     "other_db");
-    cr_repomd_set_record(repomd_obj, groupfile_rec,  "group");
-    cr_repomd_set_record(repomd_obj, compressed_groupfile_rec, "group_gz");
-    cr_repomd_set_record(repomd_obj, updateinfo_rec, "updateinfo");
+    cr_repomd_set_record(repomd_obj, pri_xml_rec);
+    cr_repomd_set_record(repomd_obj, fil_xml_rec);
+    cr_repomd_set_record(repomd_obj, oth_xml_rec);
+    cr_repomd_set_record(repomd_obj, pri_db_rec);
+    cr_repomd_set_record(repomd_obj, fil_db_rec);
+    cr_repomd_set_record(repomd_obj, oth_db_rec);
+    cr_repomd_set_record(repomd_obj, groupfile_rec);
+    cr_repomd_set_record(repomd_obj, compressed_groupfile_rec);
+    cr_repomd_set_record(repomd_obj, updateinfo_rec);
 
     int i = 0;
     while (cmd_options->repo_tags && cmd_options->repo_tags[i])
index 8fe6e6f..690bc1f 100644 (file)
@@ -1162,9 +1162,9 @@ dump_merged_metadata(GHashTable *merged_hashtable,
 
     // Prepare repomd records
 
-    cr_RepomdRecord *pri_xml_rec = cr_repomd_record_new(pri_xml_filename);
-    cr_RepomdRecord *fil_xml_rec = cr_repomd_record_new(fil_xml_filename);
-    cr_RepomdRecord *oth_xml_rec = cr_repomd_record_new(oth_xml_filename);
+    cr_RepomdRecord *pri_xml_rec = cr_repomd_record_new(pri_xml_filename, "primary");
+    cr_RepomdRecord *fil_xml_rec = cr_repomd_record_new(fil_xml_filename, "filelists");
+    cr_RepomdRecord *oth_xml_rec = cr_repomd_record_new(oth_xml_filename, "other");
     cr_RepomdRecord *pri_db_rec               = NULL;
     cr_RepomdRecord *fil_db_rec               = NULL;
     cr_RepomdRecord *oth_db_rec               = NULL;
@@ -1184,8 +1184,8 @@ dump_merged_metadata(GHashTable *merged_hashtable,
     // Groupfile
 
     if (groupfile) {
-        groupfile_rec = cr_repomd_record_new(groupfile);
-        compressed_groupfile_rec = cr_repomd_record_new(groupfile);
+        groupfile_rec = cr_repomd_record_new(groupfile, "group");
+        compressed_groupfile_rec = cr_repomd_record_new(groupfile, "group_gz");
         cr_repomd_record_compress_and_fill(groupfile_rec,
                                            compressed_groupfile_rec,
                                            CR_CHECKSUM_SHA256,
@@ -1197,7 +1197,7 @@ dump_merged_metadata(GHashTable *merged_hashtable,
     // Update info
 
     if (!cmd_options->noupdateinfo) {
-        update_info_rec = cr_repomd_record_new(update_info_filename);
+        update_info_rec = cr_repomd_record_new(update_info_filename, "updateinfo");
         cr_repomd_record_fill(update_info_rec, CR_CHECKSUM_SHA256, NULL);
     }
 
@@ -1206,7 +1206,7 @@ dump_merged_metadata(GHashTable *merged_hashtable,
 
     if (cmd_options->koji) {
         gchar *pkgorigins_path = g_strconcat(cmd_options->tmp_out_repo, "pkgorigins.gz", NULL);
-        pkgorigins_rec = cr_repomd_record_new(pkgorigins_path);
+        pkgorigins_rec = cr_repomd_record_new(pkgorigins_path, "origin");
         cr_repomd_record_fill(pkgorigins_rec, CR_CHECKSUM_SHA256, NULL);
         g_free(pkgorigins_path);
     }
@@ -1250,9 +1250,9 @@ dump_merged_metadata(GHashTable *merged_hashtable,
         remove(oth_db_filename);
 
         // Prepare repomd records
-        pri_db_rec = cr_repomd_record_new(pri_db_c_filename);
-        fil_db_rec = cr_repomd_record_new(fil_db_c_filename);
-        oth_db_rec = cr_repomd_record_new(oth_db_c_filename);
+        pri_db_rec = cr_repomd_record_new(pri_db_c_filename, "primary_db");
+        fil_db_rec = cr_repomd_record_new(fil_db_c_filename, "filelists_db");
+        oth_db_rec = cr_repomd_record_new(oth_db_c_filename, "other_db");
 
         g_free(pri_db_filename);
         g_free(fil_db_filename);
@@ -1287,16 +1287,16 @@ dump_merged_metadata(GHashTable *merged_hashtable,
     // Gen repomd.xml content
 
     cr_Repomd *repomd_obj = cr_repomd_new();
-    cr_repomd_set_record(repomd_obj, pri_xml_rec,   "primary");
-    cr_repomd_set_record(repomd_obj, fil_xml_rec,   "filelists");
-    cr_repomd_set_record(repomd_obj, oth_xml_rec,   "other");
-    cr_repomd_set_record(repomd_obj, pri_db_rec,    "primary_db");
-    cr_repomd_set_record(repomd_obj, fil_db_rec,    "filelists_db");
-    cr_repomd_set_record(repomd_obj, oth_db_rec,    "other_db");
-    cr_repomd_set_record(repomd_obj, groupfile_rec, "group");
-    cr_repomd_set_record(repomd_obj, compressed_groupfile_rec, "group_gz");
-    cr_repomd_set_record(repomd_obj, update_info_rec,"updateinfo");
-    cr_repomd_set_record(repomd_obj, pkgorigins_rec, "origin");
+    cr_repomd_set_record(repomd_obj, pri_xml_rec);
+    cr_repomd_set_record(repomd_obj, fil_xml_rec);
+    cr_repomd_set_record(repomd_obj, oth_xml_rec);
+    cr_repomd_set_record(repomd_obj, pri_db_rec);
+    cr_repomd_set_record(repomd_obj, fil_db_rec);
+    cr_repomd_set_record(repomd_obj, oth_db_rec);
+    cr_repomd_set_record(repomd_obj, groupfile_rec);
+    cr_repomd_set_record(repomd_obj, compressed_groupfile_rec);
+    cr_repomd_set_record(repomd_obj, update_info_rec);
+    cr_repomd_set_record(repomd_obj, pkgorigins_rec);
 
     char *repomd_xml = cr_repomd_xml_dump(repomd_obj);
 
index 9106079..e0ae838 100644 (file)
@@ -67,7 +67,7 @@ Repomd = _createrepo_c.Repomd
 
 class RepomdRecord(_createrepo_c.RepomdRecord):
     def compress_and_fill(self, hashtype, compresstype):
-        rec = RepomdRecord("")
+        rec = RepomdRecord(self.type + "_gz", None)
         _createrepo_c.RepomdRecord.compress_and_fill(self, rec, hashtype, compresstype)
         return rec
 
@@ -113,6 +113,7 @@ xml_dump            = _createrepo_c.xml_dump
 xml_parse_primary   = _createrepo_c.xml_parse_primary
 xml_parse_filelists = _createrepo_c.xml_parse_filelists
 xml_parse_other     = _createrepo_c.xml_parse_other
+xml_parse_repomd    = _createrepo_c.xml_parse_repomd
 
 def package_from_rpm(filename, checksum_type=SHA256, location_href=None,
                      location_base=None, changelog_limit=10):
index 8f5cb0b..f191554 100644 (file)
@@ -52,6 +52,8 @@ static struct PyMethodDef createrepo_c_methods[] = {
      METH_VARARGS, NULL},
     {"xml_parse_other",         (PyCFunction)py_xml_parse_other,
      METH_VARARGS, NULL},
+    {"xml_parse_repomd",        (PyCFunction)py_xml_parse_repomd,
+     METH_VARARGS, NULL},
     { NULL }
 };
 
index bd88c90..937f4f7 100644 (file)
@@ -241,16 +241,21 @@ ht_keys(_MetadataObject *self, PyObject *args)
 
     if (check_MetadataStatus(self))
         return NULL;
+
     GList *keys = g_hash_table_get_keys(self->md->ht);
     PyObject *list = PyList_New(0);
+
     for (GList *elem = keys; elem; elem = g_list_next(elem)) {
         PyObject *py_str = PyString_FromString(elem->data);
         assert(py_str);
         if (PyList_Append(list, py_str) == -1) {
             Py_XDECREF(list);
+            g_list_free(keys);
             return NULL;
         }
     }
+
+    g_list_free(keys);
     return list;
 }
 
index 39467fe..87f7d49 100644 (file)
@@ -31,7 +31,17 @@ typedef struct {
     cr_Repomd *repomd;
 } _RepomdObject;
 
-static int
+cr_Repomd *
+Repomd_FromPyObject(PyObject *o)
+{
+    if (!RepomdObject_Check(o)) {
+        PyErr_SetString(PyExc_TypeError, "Expected a createrepo_c.Repomd object.");
+        return NULL;
+    }
+    return ((_RepomdObject *)o)->repomd;
+}
+
+    static int
 check_RepomdStatus(const _RepomdObject *self)
 {
     assert(self != NULL);
@@ -100,14 +110,16 @@ static PyObject *
 set_record(_RepomdObject *self, PyObject *args)
 {
     PyObject *record;
-    char *type;
+    cr_RepomdRecord *orig, *new;
 
-    if (!PyArg_ParseTuple(args, "O!s:set_record", &RepomdRecord_Type, &record, &type))
+    if (!PyArg_ParseTuple(args, "O!:set_record", &RepomdRecord_Type, &record))
         return NULL;
     if (check_RepomdStatus(self))
         return NULL;
-    cr_repomd_set_record(self->repomd, RepomdRecord_FromPyObject(record), type);
-    Py_XINCREF(record);
+
+    orig = RepomdRecord_FromPyObject(record);
+    new = cr_repomd_record_copy(orig);
+    cr_repomd_set_record(self->repomd, new);
     Py_RETURN_NONE;
 }
 
@@ -183,6 +195,171 @@ static struct PyMethodDef repomd_methods[] = {
     {NULL} /* sentinel */
 };
 
+/* Convertors for getsetters */
+
+/** Convert C object to PyObject.
+ * @param       C object
+ * @return      PyObject representation
+ */
+typedef PyObject *(*ConversionFromFunc)(void *);
+
+/** Check an element from a list if has a valid format.
+ * @param       a single list element
+ * @return      0 if ok, 1 otherwise
+ */
+typedef int (*ConversionToCheckFunc)(PyObject *);
+
+/** Convert PyObject to C representation.
+ * @param       PyObject
+ * @return      C representation
+ */
+typedef void *(*ConversionToFunc)(PyObject *, GStringChunk *);
+
+static int
+CheckPyString(PyObject *dep)
+{
+    if (!PyString_Check(dep)) {
+        PyErr_SetString(PyExc_ValueError, "Element of list has to be a string");
+        return 1;
+    }
+    return 0;
+}
+
+static int
+CheckPyDistroTag(PyObject *dep)
+{
+    if (!PyTuple_Check(dep) || PyTuple_Size(dep) != 2) {
+        PyErr_SetString(PyExc_ValueError, "Element of list has to be a tuple with 2 items.");
+        return 1;
+    }
+    return 0;
+}
+
+PyObject *
+PyObject_FromRepomdRecord(cr_RepomdRecord *rec)
+{
+    return Object_FromRepomdRecord(cr_repomd_record_copy(rec));
+}
+
+typedef struct {
+    size_t offset;          /*!< Ofset of the list in cr_Repomd */
+    ConversionFromFunc f;   /*!< Conversion func to PyObject from a C object */
+    ConversionToCheckFunc t_check; /*!< Check func for a single element of list */
+    ConversionToFunc t;     /*!< Conversion func to C object from PyObject */
+} ListConvertor;
+
+/** List of convertors for converting a lists in cr_Package. */
+static ListConvertor list_convertors[] = {
+    { offsetof(cr_Repomd, repo_tags),    PyStringOrNone_FromString,
+      CheckPyString, PyObject_ToChunkedString },
+    { offsetof(cr_Repomd, distro_tags),  PyObject_FromDistroTag,
+      CheckPyDistroTag, PyObject_ToDistroTag },
+    { offsetof(cr_Repomd, content_tags), PyStringOrNone_FromString,
+      CheckPyString, PyObject_ToChunkedString },
+    { offsetof(cr_Repomd, records),      PyObject_FromRepomdRecord,
+      NULL, NULL },
+};
+
+/* Getters */
+
+static PyObject *
+get_str(_RepomdObject *self, void *member_offset)
+{
+    if (check_RepomdStatus(self))
+        return NULL;
+    cr_Repomd *repomd = self->repomd;
+    char *str = *((char **) ((size_t) repomd + (size_t) member_offset));
+    if (str == NULL)
+        Py_RETURN_NONE;
+    return PyString_FromString(str);
+}
+
+static PyObject *
+get_list(_RepomdObject *self, void *conv)
+{
+    ListConvertor *convertor = conv;
+    PyObject *list;
+    cr_Repomd *repomd = self->repomd;
+    GSList *glist = *((GSList **) ((size_t) repomd + (size_t) convertor->offset));
+
+    if (check_RepomdStatus(self))
+        return NULL;
+
+    if ((list = PyList_New(0)) == NULL)
+        return NULL;
+
+    for (GSList *elem = glist; elem; elem = g_slist_next(elem))
+        PyList_Append(list, convertor->f(elem->data));
+
+    return list;
+}
+
+/* Setters */
+
+static int
+set_str(_RepomdObject *self, PyObject *value, void *member_offset)
+{
+    if (check_RepomdStatus(self))
+        return -1;
+    if (!PyString_Check(value)) {
+        PyErr_SetString(PyExc_ValueError, "String expected!");
+        return -1;
+    }
+    cr_Repomd *repomd = self->repomd;
+
+    char *str = g_string_chunk_insert(repomd->chunk, PyString_AsString(value));
+    *((char **) ((size_t) repomd + (size_t) member_offset)) = str;
+    return 0;
+}
+
+static int
+set_list(_RepomdObject *self, PyObject *list, void *conv)
+{
+    ListConvertor *convertor = conv;
+    cr_Repomd *repomd = self->repomd;
+    GSList *glist = NULL;
+
+    if (check_RepomdStatus(self))
+        return -1;
+
+    if (!PyList_Check(list)) {
+        PyErr_SetString(PyExc_ValueError, "List expected!");
+        return -1;
+    }
+
+    Py_ssize_t len = PyList_Size(list);
+
+    // Check all elements
+    for (Py_ssize_t x = 0; x < len; x++) {
+        PyObject *elem = PyList_GetItem(list, x);
+        if (convertor->t_check && convertor->t_check(elem))
+            return -1;
+    }
+
+    for (Py_ssize_t x = 0; x < len; x++) {
+        glist = g_slist_prepend(glist,
+                        convertor->t(PyList_GetItem(list, x), repomd->chunk));
+    }
+
+    *((GSList **) ((size_t) repomd + (size_t) convertor->offset)) = glist;
+    return 0;
+}
+
+/** Return offset of a selected member of cr_Repomd structure. */
+#define OFFSET(member) (void *) offsetof(cr_Repomd, member)
+
+static PyGetSetDef repomd_getsetters[] = {
+    {"revision",         (getter)get_str,  (setter)set_str,  NULL, OFFSET(revision)},
+    {"repo_tags",        (getter)get_list, (setter)set_list, NULL, &(list_convertors[0])},
+    {"distro_tags",      (getter)get_list, (setter)set_list, NULL, &(list_convertors[1])},
+    {"content_tags",     (getter)get_list, (setter)set_list, NULL, &(list_convertors[2])},
+    {"records",          (getter)get_list, (setter)NULL,     NULL, &(list_convertors[3])},
+    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
+};
+
+/* Object */
+
+
 PyTypeObject Repomd_Type = {
     PyObject_HEAD_INIT(NULL)
     0,                              /* ob_size */
@@ -214,7 +391,7 @@ PyTypeObject Repomd_Type = {
     0,                              /* tp_iternext */
     repomd_methods,                 /* tp_methods */
     0,                              /* tp_members */
-    0,                              /* tp_getset */
+    repomd_getsetters,              /* tp_getset */
     0,                              /* tp_base */
     0,                              /* tp_dict */
     0,                              /* tp_descr_get */
index 6d44bb5..8d7e27f 100644 (file)
@@ -26,4 +26,6 @@ extern PyTypeObject Repomd_Type;
 
 #define RepomdObject_Check(o)   PyObject_TypeCheck(o, &Repomd_Type)
 
+cr_Repomd *Repomd_FromPyObject(PyObject *o);
+
 #endif
index 55104e7..9f60cac 100644 (file)
@@ -30,6 +30,23 @@ typedef struct {
     cr_RepomdRecord *record;
 } _RepomdRecordObject;
 
+PyObject *
+Object_FromRepomdRecord(cr_RepomdRecord *rec)
+{
+    PyObject *py_rec;
+
+    if (!rec) {
+        PyErr_SetString(PyExc_TypeError, "Expected a cr_RepomdRecord pointer not NULL.");
+        return NULL;
+    }
+
+    py_rec = PyObject_CallObject((PyObject *) &RepomdRecord_Type, NULL);
+    cr_repomd_record_free(((_RepomdRecordObject *)py_rec)->record);
+    ((_RepomdRecordObject *)py_rec)->record = rec;
+
+    return py_rec;
+}
+
 cr_RepomdRecord *
 RepomdRecord_FromPyObject(PyObject *o)
 {
@@ -71,18 +88,17 @@ repomdrecord_init(_RepomdRecordObject *self, PyObject *args, PyObject *kwds)
 {
     CR_UNUSED(kwds);
 
-    char *path;
+    char *type = NULL, *path = NULL;
 
-    if (!PyArg_ParseTuple(args, "s|:repomdrecord_init", &path))
+    if (!PyArg_ParseTuple(args, "|zz:repomdrecord_init", &type, &path))
         return -1;
 
     /* Free all previous resources when reinitialization */
-    if (self->record) {
+    if (self->record)
         cr_repomd_record_free(self->record);
-    }
 
     /* Init */
-    self->record = cr_repomd_record_new(path);
+    self->record = cr_repomd_record_new(type, path);
     if (self->record == NULL) {
         PyErr_SetString(CrErr_Exception, "RepomdRecord initialization failed");
         return -1;
@@ -103,12 +119,25 @@ static PyObject *
 repomdrecord_repr(_RepomdRecordObject *self)
 {
     CR_UNUSED(self);
-    return PyString_FromFormat("<createrepo_c.RepomdRecord object>");
+    if (self->record->type)
+        return PyString_FromFormat("<createrepo_c.RepomdRecord %s object>",
+                                   self->record->type);
+    else
+        return PyString_FromFormat("<createrepo_c.RepomdRecord object>");
 }
 
 /* RepomdRecord methods */
 
 static PyObject *
+copy_repomdrecord(_RepomdRecordObject *self, void *nothing)
+{
+    CR_UNUSED(nothing);
+    if (check_RepomdRecordStatus(self))
+        return NULL;
+    return Object_FromRepomdRecord(cr_repomd_record_copy(self->record));
+}
+
+static PyObject *
 fill(_RepomdRecordObject *self, PyObject *args)
 {
     int checksum_type;
@@ -179,6 +208,7 @@ rename_file(_RepomdRecordObject *self, void *nothing)
 }
 
 static struct PyMethodDef repomdrecord_methods[] = {
+    {"copy", (PyCFunction)copy_repomdrecord, METH_NOARGS, NULL},
     {"fill", (PyCFunction)fill, METH_VARARGS, NULL},
     {"compress_and_fill", (PyCFunction)compress_and_fill, METH_VARARGS, NULL},
     {"rename_file", (PyCFunction)rename_file, METH_NOARGS, NULL},
@@ -274,6 +304,7 @@ set_str(_RepomdRecordObject *self, PyObject *value, void *member_offset)
 }
 
 static PyGetSetDef repomdrecord_getsetters[] = {
+    {"type",                (getter)get_str, (setter)set_str, NULL, OFFSET(type)},
     {"location_real",       (getter)get_str, (setter)set_str, NULL, OFFSET(location_real)},
     {"location_href",       (getter)get_str, (setter)set_str, NULL, OFFSET(location_href)},
     {"checksum",            (getter)get_str, (setter)set_str, NULL, OFFSET(checksum)},
index ee55417..cbdcc6a 100644 (file)
 #include "src/createrepo_c.h"
 
 extern PyTypeObject RepomdRecord_Type;
-cr_RepomdRecord *RepomdRecord_FromPyObject(PyObject *o);
 
 #define RepomdRecordObject_Check(o)   PyObject_TypeCheck(o, &RepomdRecord_Type)
 
+PyObject *Object_FromRepomdRecord(cr_RepomdRecord *rec);
+cr_RepomdRecord *RepomdRecord_FromPyObject(PyObject *o);
+
 #endif
index 41e05de..b2cc013 100644 (file)
@@ -20,6 +20,8 @@
 #include <Python.h>
 #include <assert.h>
 #include "typeconversion.h"
+#include "src/createrepo_c.h"
+#include "src/repomd_internal.h"
 
 void
 PyErr_ToGError(GError **err)
@@ -69,6 +71,12 @@ PyObject_ToStrOrNull(PyObject *pyobj)
     return NULL;
 }
 
+char *
+PyObject_ToChunkedString(PyObject *pyobj, GStringChunk *chunk)
+{
+    return cr_safe_string_chunk_insert(chunk, PyObject_ToStrOrNull(pyobj));
+}
+
 long long
 PyObject_ToLongLongOrZero(PyObject *pyobj)
 {
@@ -191,6 +199,35 @@ PyObject_ToChangelogEntry(PyObject *tuple, GStringChunk *chunk)
     return log;
 }
 
+PyObject *
+PyObject_FromDistroTag(cr_DistroTag *tag)
+{
+    PyObject *tuple;
+
+    if ((tuple = PyTuple_New(2)) == NULL)
+        return NULL;
+
+    PyTuple_SetItem(tuple, 0, PyStringOrNone_FromString(tag->cpeid));
+    PyTuple_SetItem(tuple, 1, PyStringOrNone_FromString(tag->val));
+
+    return tuple;
+}
+
+cr_DistroTag *
+PyObject_ToDistroTag(PyObject *tuple, GStringChunk *chunk)
+{
+    PyObject *pyobj;
+    cr_DistroTag *tag = cr_distrotag_new();
+
+    pyobj = PyTuple_GetItem(tuple, 0);
+    tag->cpeid = cr_safe_string_chunk_insert(chunk, PyObject_ToStrOrNull(pyobj));
+
+    pyobj = PyTuple_GetItem(tuple, 2);
+    tag->val = cr_safe_string_chunk_insert(chunk, PyObject_ToStrOrNull(pyobj));
+
+    return tag;
+}
+
 GSList *
 GSList_FromPyList_Str(PyObject *py_list)
 {
index 9139e4f..dbc651d 100644 (file)
@@ -28,6 +28,7 @@ void PyErr_ToGError(GError **err);
 
 PyObject *PyStringOrNone_FromString(const char *str);
 char *PyObject_ToStrOrNull(PyObject *pyobj);
+char *PyObject_ToChunkedString(PyObject *pyobj, GStringChunk *chunk);
 
 PyObject *PyObject_FromDependency(cr_Dependency *dep);
 cr_Dependency *PyObject_ToDependency(PyObject *tuple, GStringChunk *chunk);
@@ -38,6 +39,9 @@ cr_PackageFile *PyObject_ToPackageFile(PyObject *tuple, GStringChunk *chunk);
 PyObject *PyObject_FromChangelogEntry(cr_ChangelogEntry *log);
 cr_ChangelogEntry *PyObject_ToChangelogEntry(PyObject *tuple, GStringChunk *chunk);
 
+PyObject *PyObject_FromDistroTag(cr_DistroTag *tag);
+cr_DistroTag *PyObject_ToDistroTag(PyObject *tuple, GStringChunk *chunk);
+
 GSList *GSList_FromPyList_Str(PyObject *py_list);
 
 #endif
index b46a7c0..63fe514 100644 (file)
@@ -26,6 +26,7 @@
 #include "xml_parser-py.h"
 #include "typeconversion.h"
 #include "package-py.h"
+#include "repomd-py.h"
 #include "exception-py.h"
 
 typedef struct {
@@ -372,3 +373,64 @@ py_xml_parse_other(PyObject *self, PyObject *args)
 
     Py_RETURN_NONE;
 }
+
+PyObject *
+py_xml_parse_repomd(PyObject *self, PyObject *args)
+{
+    CR_UNUSED(self);
+
+    char *filename;
+    PyObject *py_repomd, *py_warningcb;
+    CbData cbdata;
+    cr_Repomd *repomd;
+    GError *tmp_err = NULL;
+
+    if (!PyArg_ParseTuple(args, "sOO:py_xml_parse_repomd",
+                                         &filename,
+                                         &py_repomd,
+                                         &py_warningcb)) {
+        return NULL;
+    }
+
+    if (!RepomdObject_Check(py_repomd)) {
+        PyErr_SetString(PyExc_TypeError, "Bad type");
+        return NULL;
+    }
+
+    if (!PyCallable_Check(py_warningcb) && py_warningcb != Py_None) {
+        PyErr_SetString(PyExc_TypeError, "warningcb must be callable or None");
+        return NULL;
+    }
+
+    Py_XINCREF(py_repomd);
+    Py_XINCREF(py_warningcb);
+
+    cr_XmlParserWarningCb   ptr_c_warningcb = NULL;
+
+    if (py_warningcb != Py_None)
+        ptr_c_warningcb = c_warningcb;
+
+    cbdata.py_newpkgcb  = NULL;
+    cbdata.py_pkgcb     = NULL;
+    cbdata.py_warningcb = py_warningcb;
+    cbdata.py_pkg       = NULL;
+
+    repomd = Repomd_FromPyObject(py_repomd);
+
+    cr_xml_parse_repomd(filename,
+                       repomd,
+                       ptr_c_warningcb,
+                       &cbdata,
+                       &tmp_err);
+
+    Py_XDECREF(py_repomd);
+    Py_XDECREF(py_warningcb);
+
+    if (tmp_err) {
+        PyErr_Format(CrErr_Exception, "%s", tmp_err->message);
+        g_clear_error(&tmp_err);
+        return NULL;
+    }
+
+    Py_RETURN_NONE;
+}
index 9847b45..c835afd 100644 (file)
@@ -25,5 +25,6 @@
 PyObject *py_xml_parse_primary(PyObject *self, PyObject *args);
 PyObject *py_xml_parse_filelists(PyObject *self, PyObject *args);
 PyObject *py_xml_parse_other(PyObject *self, PyObject *args);
+PyObject *py_xml_parse_repomd(PyObject *self, PyObject *args);
 
 #endif
index c73249c..7e2635d 100644 (file)
@@ -59,21 +59,12 @@ cr_distrotag_new()
     return (cr_DistroTag *) g_malloc0(sizeof(cr_DistroTag));
 }
 
-void
-cr_distrotag_free(cr_DistroTag *distro)
-{
-    if (!distro) return;
-    g_free(distro->cpeid);
-    g_free(distro->val);
-    g_free(distro);
-}
-
-
 cr_RepomdRecord *
-cr_repomd_record_new(const char *path)
+cr_repomd_record_new(const char *type, const char *path)
 {
     cr_RepomdRecord *md = g_malloc0(sizeof(*md));
-    md->chunk = g_string_chunk_new(1024);
+    md->chunk = g_string_chunk_new(128);
+    md->type  = cr_safe_string_chunk_insert(md->chunk, type);
     if (path) {
         gchar *filename = cr_get_filename(path);
         gchar *location_href = g_strconcat(LOCATION_HREF_PREFIX, filename, NULL);
@@ -84,8 +75,6 @@ cr_repomd_record_new(const char *path)
     return md;
 }
 
-
-
 void
 cr_repomd_record_free(cr_RepomdRecord *md)
 {
@@ -96,6 +85,33 @@ cr_repomd_record_free(cr_RepomdRecord *md)
     g_free(md);
 }
 
+cr_RepomdRecord *
+cr_repomd_record_copy(const cr_RepomdRecord *orig)
+{
+    cr_RepomdRecord *rec;
+
+    if (!orig) return NULL;
+
+    rec = cr_repomd_record_new(orig->type, NULL);
+    rec->location_real      = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->location_real);
+    rec->location_href      = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->location_href);
+    rec->checksum           = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->checksum);
+    rec->checksum_type      = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->checksum_type);
+    rec->checksum_open      = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->checksum_open);
+    rec->checksum_open_type = cr_safe_string_chunk_insert(rec->chunk,
+                                                orig->checksum_open_type);
+    rec->timestamp = orig->timestamp;
+    rec->size      = orig->size;
+    rec->size_open = orig->size_open;
+    rec->db_ver    = orig->db_ver;
+
+    return rec;
+}
 
 contentStat *
 cr_get_compressed_content_stat(const char *filename,
@@ -174,8 +190,6 @@ cr_get_compressed_content_stat(const char *filename,
     return result;
 }
 
-
-
 int
 cr_repomd_record_fill(cr_RepomdRecord *md,
                       cr_ChecksumType checksum_type,
@@ -300,7 +314,6 @@ cr_repomd_record_fill(cr_RepomdRecord *md,
     return CRE_OK;
 }
 
-
 int
 cr_repomd_record_compress_and_fill(cr_RepomdRecord *record,
                                    cr_RepomdRecord *crecord,
@@ -473,7 +486,6 @@ cr_repomd_record_compress_and_fill(cr_RepomdRecord *record,
     return CRE_OK;
 }
 
-
 int
 cr_repomd_record_rename_file(cr_RepomdRecord *md, GError **err)
 {
@@ -584,21 +596,18 @@ cr_repomd_record_rename_file(cr_RepomdRecord *md, GError **err)
     return CRE_OK;
 }
 
-
 void
-cr_repomd_dump_data_items(xmlNodePtr root,
-                          cr_RepomdRecord *md,
-                          const xmlChar *type)
+cr_repomd_dump_data_items(xmlNodePtr root, cr_RepomdRecord *md)
 {
     xmlNodePtr data, node;
     gchar str_buffer[STR_BUFFER_SIZE];
 
-    if (!root || !md || !type) {
+    if (!root || !md) {
         return;
     }
 
     data = xmlNewChild(root, NULL, BAD_CAST "data", NULL);
-    xmlNewProp(data, BAD_CAST "type", BAD_CAST type);
+    xmlNewProp(data, BAD_CAST "type", BAD_CAST md->type);
 
 
     node = xmlNewTextChild(data, NULL, BAD_CAST "checksum",
@@ -625,20 +634,19 @@ cr_repomd_dump_data_items(xmlNodePtr root,
         xmlNewChild(data, NULL, BAD_CAST "open-size", BAD_CAST str_buffer);
     }
 
-    if (g_str_has_suffix((char *)type, "_db")) {
+    if (g_str_has_suffix((char *)md->type, "_db")) {
         g_snprintf(str_buffer, STR_BUFFER_SIZE, "%d", md->db_ver);
         xmlNewChild(data, NULL, BAD_CAST "database_version",
                     BAD_CAST str_buffer);
     }
 }
 
-
 char *
 cr_repomd_xml_dump(cr_Repomd *repomd)
 {
     xmlDocPtr doc;
     xmlNodePtr root;
-    GList *keys, *element;
+    GSList *element;
 
 
     // Start of XML document
@@ -691,17 +699,13 @@ cr_repomd_xml_dump(cr_Repomd *repomd)
 
     // Records
 
-    keys = g_hash_table_get_keys(repomd->records);
-    keys = g_list_sort(keys, (GCompareFunc) g_strcmp0);
+    repomd->records = g_slist_sort(repomd->records, (GCompareFunc) g_strcmp0);
 
-    for (element = keys; element; element = g_list_next(element)) {
-        char *type = element->data;
-        cr_RepomdRecord *rec = g_hash_table_lookup(repomd->records, type);
-        cr_repomd_dump_data_items(root, rec, (const xmlChar *) type);
+    for (element = repomd->records; element; element = g_slist_next(element)) {
+        cr_RepomdRecord *rec = element->data;
+        cr_repomd_dump_data_items(root, rec);
     }
 
-    g_list_free(keys);
-
     // Dump IT!
 
     char *result;
@@ -719,52 +723,41 @@ cr_repomd_xml_dump(cr_Repomd *repomd)
     return result;
 }
 
-
 cr_Repomd *
 cr_repomd_new()
 {
    cr_Repomd *repomd = g_malloc0(sizeof(cr_Repomd));
-   repomd->records = g_hash_table_new_full(g_str_hash,
-                                           g_str_equal,
-                                           g_free,
-                                           (GDestroyNotify) cr_repomd_record_free);
+   repomd->chunk = g_string_chunk_new(0);
    return repomd;
 }
 
-
 void
 cr_repomd_free(cr_Repomd *repomd)
 {
     if (!repomd) return;
-    g_hash_table_destroy(repomd->records);
-    cr_slist_free_full(repomd->repo_tags, g_free);
-    cr_slist_free_full(repomd->distro_tags, (GDestroyNotify) cr_distrotag_free);
-    cr_slist_free_full(repomd->content_tags, g_free);
-    g_free(repomd->revision);
+    cr_slist_free_full(repomd->records, (GDestroyNotify) cr_repomd_record_free );
+    g_slist_free(repomd->repo_tags);
+    cr_slist_free_full(repomd->distro_tags, (GDestroyNotify) g_free);
+    g_slist_free(repomd->content_tags);
+    g_string_chunk_free(repomd->chunk);
     g_free(repomd);
 }
 
-
 void
 cr_repomd_set_record(cr_Repomd *repomd,
-                     cr_RepomdRecord *record,
-                     const char *type)
+                     cr_RepomdRecord *record)
 {
     if (!repomd || !record) return;
-    g_hash_table_replace(repomd->records, g_strdup(type), record);
+    repomd->records = g_slist_append(repomd->records, record);
 }
 
-
 void
 cr_repomd_set_revision(cr_Repomd *repomd, const char *revision)
 {
     if (!repomd) return;
-    if (repomd->revision)  // A revision string already exists
-        g_free(repomd->revision);
-    repomd->revision = g_strdup(revision);
+    repomd->revision = cr_safe_string_chunk_insert(repomd->chunk, revision);
 }
 
-
 void
 cr_repomd_add_distro_tag(cr_Repomd *repomd,
                          const char *cpeid,
@@ -773,25 +766,25 @@ cr_repomd_add_distro_tag(cr_Repomd *repomd,
     cr_DistroTag *distro;
     if (!repomd || !tag) return;
     distro = cr_distrotag_new();
-    distro->cpeid = g_strdup(cpeid);
-    distro->val   = g_strdup(tag);
+    distro->cpeid = cr_safe_string_chunk_insert(repomd->chunk, cpeid);
+    distro->val   = cr_safe_string_chunk_insert(repomd->chunk, tag);
     repomd->distro_tags = g_slist_prepend(repomd->distro_tags,
                                           (gpointer) distro);
 }
 
-
 void
 cr_repomd_add_repo_tag(cr_Repomd *repomd, const char *tag)
 {
-    if (!repomd) return;
-    repomd->repo_tags = g_slist_append(repomd->repo_tags, g_strdup(tag));
+    if (!repomd || !tag) return;
+    repomd->repo_tags = g_slist_append(repomd->repo_tags,
+                            cr_safe_string_chunk_insert(repomd->chunk, tag));
 }
 
-
 void
 cr_repomd_add_content_tag(cr_Repomd *repomd, const char *tag)
 {
-    if (!repomd) return;
-    repomd->content_tags = g_slist_append(repomd->content_tags, g_strdup(tag));
+    if (!repomd || !tag) return;
+    repomd->content_tags = g_slist_append(repomd->content_tags,
+                            cr_safe_string_chunk_insert(repomd->chunk, tag));
 }
 
index 669238b..6b8b5ba 100644 (file)
@@ -67,6 +67,7 @@ extern "C" {
 /** Internal representation of cr_RepomdRecord object
  */
 typedef struct {
+    char *type;                 /*!< type of record */
     char *location_real;        /*!< real path to the file */
     char *location_href;        /*!< location of the file (in repomd.xml) */
     char *checksum;             /*!< checksum of file */
@@ -78,7 +79,7 @@ typedef struct {
     long size_open;             /*!< size of uncompressed file in bytes */
     int db_ver;                 /*!< version of database */
 
-    GStringChunk *chunk;        /*!< string chunk */
+    GStringChunk *chunk;        /*!< String chunk */
 } cr_RepomdRecord;
 
 /** Distro tag structure
@@ -91,17 +92,22 @@ typedef struct {
 /** Internal representation of cr_Repomd object
  */
 typedef struct {
-    GHashTable *records;        /*!< Hash table with cr_RepomdRecord */
+    gchar *revision;            /*!< Revison */
     GSList *repo_tags;          /*!< List of strings */
-    GSList *distro_tags;        /*!< List of cr_DistroTag* */
     GSList *content_tags;       /*!< List of strings */
-    gchar *revision;
+    GSList *distro_tags;        /*!< List of cr_DistroTag* */
+    GSList *records;            /*!< List with cr_RepomdRecords */
+
+    GStringChunk *chunk;        /*!< String chunk for repomd strings
+                                     (Note: RepomdRecord strings are stored
+                                      in RepomdRecord->chunk) */
 } cr_Repomd;
 
 /** Creates (alloc) new cr_RepomdRecord object
+ * @param type                  Type of record ("primary", "filelists", ..)
  * @param path                  path to the compressed file
  */
-cr_RepomdRecord *cr_repomd_record_new(const char *path);
+cr_RepomdRecord *cr_repomd_record_new(const char *type, const char *path);
 
 /** Destroy cr_RepomdRecord object.
  * NOTE: Do NOT use this function on objects attached to cr_Repomd
@@ -110,6 +116,12 @@ cr_RepomdRecord *cr_repomd_record_new(const char *path);
  */
 void cr_repomd_record_free(cr_RepomdRecord *record);
 
+/** Copy cr_RepomdRecord object.
+ * @param orig              cr_RepomdRecord object
+ * @return                  copy of cr_RepomdRecord object
+ */
+cr_RepomdRecord *cr_repomd_record_copy(const cr_RepomdRecord *orig);
+
 /** Fill unfilled items in the cr_RepomdRecord (calculate checksums,
  * get file size before/after compression, etc.).
  * Note: For groupfile you shoud use cr_repomd_record_compress_and_fill
@@ -154,11 +166,8 @@ cr_Repomd *cr_repomd_new();
 /** Set cr_Repomd record into cr_Repomd object.
  * @param repomd                cr_Repomd object
  * @param record                cr_RepomdRecord object
- * @param type                  type of record ("primary, "groupfile", ...)
  */
-void cr_repomd_set_record(cr_Repomd *repomd,
-                          cr_RepomdRecord *record,
-                          const char *type);
+void cr_repomd_set_record(cr_Repomd *repomd, cr_RepomdRecord *record);
 
 /** Set custom revision string of repomd.
  * @param repomd                cr_Repomd object
index 14457ba..946e493 100644 (file)
@@ -29,8 +29,6 @@ extern "C" {
 
 cr_DistroTag *cr_distrotag_new();
 
-void cr_distrotag_free(cr_DistroTag *distro);
-
 #ifdef __cplusplus
 }
 #endif
index 81fe8d6..70b1f2a 100644 (file)
@@ -96,6 +96,7 @@ cr_xml_parser_warning(cr_ParserData *pd,
 
     tmp_err = NULL;
     ret = pd->warningcb(type, warn, pd->warningcb_data, &tmp_err);
+    g_free(warn);
     if (ret != CR_CB_RET_OK) {
         if (tmp_err)
             g_propagate_prefixed_error(&pd->err, tmp_err,
index 8a07abc..0679023 100644 (file)
@@ -81,7 +81,8 @@ typedef int (*cr_XmlParserPkgCb)(cr_Package *pkg,
  * and ignored by default. But if callback return CR_CB_RET_ERR instead of
  * CR_CB_RET_OK then parsing is immediately interrupted.
  * @param type      Type of warning
- * @param msg       Warning msg
+ * @param msg       Warning msg. The message is destroyed after the call.
+ *                  If you want touse the message later, you have to copy it.
  * @param cbdata    User data.
  * @param err       GError **
  * @return          CR_CB_RET_OK (0) or CR_CB_RET_ERR (1) - stops the parsing
index 12d5e2d..d0e4a94 100644 (file)
@@ -144,8 +144,6 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
         assert(pd->repomd);
         assert(!pd->repomdrecord);
 
-        pd->repomdrecord = cr_repomd_record_new(NULL);
-
         val = cr_find_attr("type", attr);
         if (!val) {
             cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
@@ -153,7 +151,8 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
             val = "unknown";
         }
 
-        cr_repomd_set_record(pd->repomd, pd->repomdrecord, val);
+        pd->repomdrecord = cr_repomd_record_new(val, NULL);
+        cr_repomd_set_record(pd->repomd, pd->repomdrecord);
         break;
 
     case STATE_LOCATION:
@@ -162,14 +161,18 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
 
         val = cr_find_attr("href", attr);
         if (val)
-            pd->repomdrecord->location_href = g_strdup(val);
+            pd->repomdrecord->location_href = g_string_chunk_insert(
+                                                    pd->repomdrecord->chunk,
+                                                    val);
         else
             cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
                     "Missing attribute \"href\" of a location element");
 
 //        val = cr_find_attr("base", attr);
 //        if (val)
-//            pd->repomdrecord->location_base = g_strdup(val);
+//            pd->repomdrecord->location_base = g_string_chunk_insert(
+//                                                    pd->repodmrecord->chunk,
+//                                                    val);
 
         break;
 
@@ -184,7 +187,9 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
             break;
         }
 
-        pd->repomdrecord->checksum_type = g_strdup(val);
+        pd->repomdrecord->checksum_type = g_string_chunk_insert(
+                                                    pd->repomdrecord->chunk,
+                                                    val);
         break;
 
     case STATE_OPENCHECKSUM:
@@ -198,7 +203,9 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
             break;
         }
 
-        pd->repomdrecord->checksum_open_type = g_strdup(val);
+        pd->repomdrecord->checksum_open_type = g_string_chunk_insert(
+                                                    pd->repomdrecord->chunk,
+                                                    val);
         break;
 
     case STATE_TIMESTAMP:
@@ -247,7 +254,7 @@ cr_end_handler(void *pdata, const char *element)
             break;
         }
 
-        pd->repomd->revision = g_strdup(pd->content);
+        cr_repomd_set_revision(pd->repomd, pd->content);
         break;
 
     case STATE_TAGS:
@@ -292,14 +299,18 @@ cr_end_handler(void *pdata, const char *element)
         assert(pd->repomd);
         assert(pd->repomdrecord);
 
-        pd->repomdrecord->checksum = g_strdup(pd->content);
+        pd->repomdrecord->checksum = cr_safe_string_chunk_insert(
+                                            pd->repomdrecord->chunk,
+                                            pd->content);
         break;
 
     case STATE_OPENCHECKSUM:
         assert(pd->repomd);
         assert(pd->repomdrecord);
 
-        pd->repomdrecord->checksum_open = g_strdup(pd->content);
+        pd->repomdrecord->checksum_open = cr_safe_string_chunk_insert(
+                                            pd->repomdrecord->chunk,
+                                            pd->content);
         break;
 
     case STATE_TIMESTAMP:
index 3411664..be29c74 100644 (file)
@@ -54,6 +54,7 @@ PKG_SUPER_KERNEL_PATH = os.path.join(PACKAGES_PATH, PKG_SUPER_KERNEL)
 # Test repositories
 
 REPO_00_PATH = os.path.join(REPOS_PATH, "repo_00")
+REPO_00_REPOMD = os.path.join(REPO_00_PATH, "repodata/repomd.xml")
 REPO_00_PRIXML = os.path.join(REPO_00_PATH, "repodata/",
     "dabe2ce5481d23de1f4f52bdcfee0f9af98316c9e0de2ce8123adeefa0dd08b9-primary.xml.gz")
 REPO_00_FILXML = os.path.join(REPO_00_PATH, "repodata/",
@@ -62,6 +63,7 @@ REPO_00_OTHXML = os.path.join(REPO_00_PATH, "repodata/",
     "6bf9672d0862e8ef8b8ff05a2fd0208a922b1f5978e6589d87944c88259cb670-other.xml.gz")
 
 REPO_01_PATH = os.path.join(REPOS_PATH, "repo_01")
+REPO_01_REPOMD = os.path.join(REPO_01_PATH, "repodata/repomd.xml")
 REPO_01_PRIXML = os.path.join(REPO_01_PATH, "repodata/",
     "6c662d665c24de9a0f62c17d8fa50622307739d7376f0d19097ca96c6d7f5e3e-primary.xml.gz")
 REPO_01_FILXML = os.path.join(REPO_01_PATH, "repodata/",
@@ -70,6 +72,7 @@ REPO_01_OTHXML = os.path.join(REPO_01_PATH, "repodata/",
     "b752a73d9efd4006d740f943db5fb7c2dd77a8324bd99da92e86bd55a2c126ef-other.xml.gz")
 
 REPO_02_PATH = os.path.join(REPOS_PATH, "repo_02")
+REPO_02_REPOMD = os.path.join(REPO_02_PATH, "repodata/repomd.xml")
 REPO_02_PRIXML = os.path.join(REPO_02_PATH, "repodata/",
     "bcde64b04916a2a72fdc257d61bc922c70b3d58e953499180585f7a360ce86cf-primary.xml.gz")
 REPO_02_FILXML = os.path.join(REPO_02_PATH, "repodata/",
index f55932e..24a3960 100644 (file)
@@ -20,13 +20,10 @@ class TestCaseRepomd(unittest.TestCase):
         shutil.rmtree(self.tmpdir)
 
     def xxx_repomdrecord_fill(self):
-        self.assertRaises(TypeError, cr.RepomdRecord)
-        self.assertRaises(TypeError, cr.RepomdRecord, None)
-
         shutil.copyfile(REPO_00_PRIXML, self.path00)
         self.assertTrue(os.path.exists(self.path00))
 
-        rec = cr.RepomdRecord(self.path00)
+        rec = cr.RepomdRecord("primary", self.path00)
         self.assertTrue(rec)
         rec.fill(cr.SHA256)
         rec.rename_file()
@@ -46,15 +43,28 @@ class TestCaseRepomd(unittest.TestCase):
         # Revision shoud be current Unix time
         self.assertTrue(re.search(r"<revision>[0-9]+</revision>", xml))
 
+        self.assertEqual(md.revision, None)
         md.set_revision("foobar")
+        self.assertEqual(md.revision, "foobar")
 
+        self.assertEqual(md.distro_tags, [])
         md.add_distro_tag("tag1")
         md.add_distro_tag("tag2", "cpeid1")
         md.add_distro_tag("tag3", cpeid="cpeid2")
+        self.assertEqual(md.distro_tags,
+                [('cpeid2', 'tag3'),
+                 ('cpeid1', 'tag2'),
+                 (None, 'tag1')])
 
+        self.assertEqual(md.repo_tags, [])
         md.add_repo_tag("repotag")
+        self.assertEqual(md.repo_tags, ['repotag'])
 
+        self.assertEqual(md.content_tags, [])
         md.add_content_tag("contenttag")
+        self.assertEqual(md.content_tags, ['contenttag'])
+
+        self.assertEqual(md.records, [])
 
         xml = md.xml_dump()
         self.assertEqual(xml,
@@ -71,10 +81,12 @@ class TestCaseRepomd(unittest.TestCase):
 </repomd>
 """)
 
-        rec = cr.RepomdRecord(self.path00)
+        rec = cr.RepomdRecord("primary", self.path00)
         rec.fill(cr.SHA256)
         rec.timestamp = 1
-        md.set_record(rec, "primary")
+        md.set_record(rec)
+
+        self.assertEqual(len(md.records), 1)
 
         xml = md.xml_dump()
         self.assertEqual(xml,
index f425571..48d6cf5 100644 (file)
@@ -22,13 +22,10 @@ class TestCaseRepomdRecord(unittest.TestCase):
         shutil.rmtree(self.tmpdir)
 
     def test_repomdrecord_fill(self):
-        self.assertRaises(TypeError, cr.RepomdRecord)
-        self.assertRaises(TypeError, cr.RepomdRecord, None)
-
         shutil.copyfile(REPO_00_PRIXML, self.path00)
         self.assertTrue(os.path.exists(self.path00))
 
-        rec = cr.RepomdRecord(self.path00)
+        rec = cr.RepomdRecord("primary", self.path00)
         self.assertTrue(rec)
 
         self.assertEqual(rec.location_real, self.path00)
@@ -62,17 +59,15 @@ class TestCaseRepomdRecord(unittest.TestCase):
             ['dabe2ce5481d23de1f4f52bdcfee0f9af98316c9e0de2ce8123adeefa0dd08b9-primary.xml.gz'])
 
     def test_repomdrecord_setters(self):
-        self.assertRaises(TypeError, cr.RepomdRecord)
-        self.assertRaises(TypeError, cr.RepomdRecord, None)
-
         shutil.copyfile(REPO_00_PRIXML, self.path00)
         self.assertTrue(os.path.exists(self.path00))
 
-        rec = cr.RepomdRecord(self.path00)
+        rec = cr.RepomdRecord("primary", self.path00)
         self.assertTrue(rec)
 
         rec.fill(cr.SHA256)
 
+        self.assertEqual(rec.type, "primary")
         self.assertEqual(rec.location_real, self.path00)
         self.assertEqual(rec.location_href, "repodata/primary.xml.gz")
         self.assertEqual(rec.checksum, "dabe2ce5481d23de1f4f52bdcfee0f9af98316c9e0de2ce8123adeefa0dd08b9")
@@ -86,6 +81,7 @@ class TestCaseRepomdRecord(unittest.TestCase):
 
         # Set new values
 
+        rec.type = "foo"
         rec.location_href = "repodata/foo.xml.gz"
         rec.checksum = "foobar11"
         rec.checksum_type = "foo1"
@@ -98,6 +94,7 @@ class TestCaseRepomdRecord(unittest.TestCase):
 
         # Check
 
+        self.assertEqual(rec.type, "foo")
         self.assertEqual(rec.location_real, self.path00)
         self.assertEqual(rec.location_href, "repodata/foo.xml.gz")
         self.assertEqual(rec.checksum, "foobar11")
@@ -110,13 +107,10 @@ class TestCaseRepomdRecord(unittest.TestCase):
         self.assertEqual(rec.db_ver, 11)
 
     def test_repomdrecord_compress_and_fill(self):
-        self.assertRaises(TypeError, cr.RepomdRecord)
-        self.assertRaises(TypeError, cr.RepomdRecord, None)
-
         open(self.path01, "w").write("foobar\ncontent\nhh\n")
         self.assertTrue(os.path.exists(self.path01))
 
-        rec = cr.RepomdRecord(self.path01)
+        rec = cr.RepomdRecord("primary", self.path01)
         self.assertTrue(rec)
         rec_compressed = rec.compress_and_fill(cr.SHA256, cr.GZ_COMPRESSION)
 
index fff7167..4fd42c9 100644 (file)
@@ -549,3 +549,69 @@ class TestCaseXmlParserOther(unittest.TestCase):
                           cr.xml_parse_other,
                           OTHER_MULTI_WARN_00_PATH,
                           newpkgcb, None, warningcb)
+
+class TestCaseXmlParserRepomd(unittest.TestCase):
+
+    def test_xml_parser_repomd_repo01(self):
+
+        warnings = []
+
+        def warningcb(warn_type, msg):
+            warnings.append((warn_type, msg))
+
+        repomd = cr.Repomd()
+
+        cr.xml_parse_repomd(REPO_01_REPOMD, repomd, warningcb)
+
+        self.assertEqual(warnings, [])
+
+        self.assertEqual(repomd.revision, "1334667230")
+        self.assertEqual(repomd.repo_tags, [])
+        self.assertEqual(repomd.distro_tags, [])
+        self.assertEqual(repomd.content_tags, [])
+        self.assertEqual(len(repomd.records), 3)
+
+        self.assertEqual(repomd.records[0].type, "filelists")
+        self.assertEqual(repomd.records[0].location_real, None)
+        self.assertEqual(repomd.records[0].location_href,
+            "repodata/c7db035d0e6f1b2e883a7fa3229e2d2be70c05a8b8d2b57dbb5f9c1a67483b6c-filelists.xml.gz")
+        self.assertEqual(repomd.records[0].checksum,
+            "c7db035d0e6f1b2e883a7fa3229e2d2be70c05a8b8d2b57dbb5f9c1a67483b6c")
+        self.assertEqual(repomd.records[0].checksum_type, "sha256")
+        self.assertEqual(repomd.records[0].checksum_open,
+            "85bc611be5d81ac8da2fe01e98ef741d243d1518fcc46ada70660020803fbf09")
+        self.assertEqual(repomd.records[0].checksum_open_type, "sha256")
+        self.assertEqual(repomd.records[0].timestamp, 1334667230)
+        self.assertEqual(repomd.records[0].size, 273)
+        self.assertEqual(repomd.records[0].size_open, 389)
+        self.assertEqual(repomd.records[0].db_ver, 0)
+
+        self.assertEqual(repomd.records[1].type, "other")
+        self.assertEqual(repomd.records[1].location_real, None)
+        self.assertEqual(repomd.records[1].location_href,
+            "repodata/b752a73d9efd4006d740f943db5fb7c2dd77a8324bd99da92e86bd55a2c126ef-other.xml.gz")
+        self.assertEqual(repomd.records[1].checksum,
+            "b752a73d9efd4006d740f943db5fb7c2dd77a8324bd99da92e86bd55a2c126ef")
+        self.assertEqual(repomd.records[1].checksum_type, "sha256")
+        self.assertEqual(repomd.records[1].checksum_open,
+            "da6096c924349af0c326224a33be0cdb26897fbe3d25477ac217261652449445")
+        self.assertEqual(repomd.records[1].checksum_open_type, "sha256")
+        self.assertEqual(repomd.records[1].timestamp, 1334667230)
+        self.assertEqual(repomd.records[1].size, 332)
+        self.assertEqual(repomd.records[1].size_open, 530)
+        self.assertEqual(repomd.records[1].db_ver, 0)
+
+        self.assertEqual(repomd.records[2].type, "primary")
+        self.assertEqual(repomd.records[2].location_real, None)
+        self.assertEqual(repomd.records[2].location_href,
+            "repodata/6c662d665c24de9a0f62c17d8fa50622307739d7376f0d19097ca96c6d7f5e3e-primary.xml.gz")
+        self.assertEqual(repomd.records[2].checksum,
+            "6c662d665c24de9a0f62c17d8fa50622307739d7376f0d19097ca96c6d7f5e3e")
+        self.assertEqual(repomd.records[2].checksum_type, "sha256")
+        self.assertEqual(repomd.records[2].checksum_open,
+            "0fc6cadf97d515e87491d24dc9712d8ddaf2226a21ae7f131ff42d71a877c496")
+        self.assertEqual(repomd.records[2].checksum_open_type, "sha256")
+        self.assertEqual(repomd.records[2].timestamp, 1334667230)
+        self.assertEqual(repomd.records[2].size, 782)
+        self.assertEqual(repomd.records[2].size_open, 2085)
+        self.assertEqual(repomd.records[2].db_ver, 0)