From 71da59ff5337e9bebf67492be9ddb6d7482e638f Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 28 2020 08:49:19 +0000 Subject: import createrepo_c-0.15.1-2.el8 --- diff --git a/.createrepo_c.metadata b/.createrepo_c.metadata index 5f0bcc7..3341249 100644 --- a/.createrepo_c.metadata +++ b/.createrepo_c.metadata @@ -1 +1 @@ -60f5c59be623b10b8a7282d251c496cd49083268 SOURCES/createrepo_c-0.11.0.tar.gz +e85178e66ca8c2157ef2da31cb8c25ff456631fd SOURCES/createrepo_c-0.15.1.tar.gz diff --git a/.gitignore b/.gitignore index 7b723f4..81a3d81 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/createrepo_c-0.11.0.tar.gz +SOURCES/createrepo_c-0.15.1.tar.gz diff --git a/SOURCES/0001-Consistently-produce-valid-URLs-by-prepending-protocol-RhBug1632121.patch b/SOURCES/0001-Consistently-produce-valid-URLs-by-prepending-protocol-RhBug1632121.patch deleted file mode 100644 index 72cdf63..0000000 --- a/SOURCES/0001-Consistently-produce-valid-URLs-by-prepending-protocol-RhBug1632121.patch +++ /dev/null @@ -1,121 +0,0 @@ -From f67be7b6045fb4be42ad226d0054edd685d33b9f Mon Sep 17 00:00:00 2001 -From: Aleš Matěj -Date: Tue, 12 Feb 2019 12:59:14 +0100 -Subject: [PATCH] Consistently produce valid URLs by prepending protocol. (RhBug:1632121) - ---- - src/mergerepo_c.c | 17 ++--------------- - src/xml_dump.c | 8 ++++++++ - src/xml_dump.h | 8 ++++++++ - src/xml_dump_primary.c | 6 ++++-- - 4 files changed, 22 insertions(+), 17 deletions(-) - -diff --git a/src/mergerepo_c.c b/src/mergerepo_c.c -index 94b929c..1ae3a9b 100644 ---- a/src/mergerepo_c.c -+++ b/src/mergerepo_c.c -@@ -496,17 +496,6 @@ cr_srpm_val_destroy(gpointer data) - } - - --/** Prepend protocol if necessary -- */ --static gchar * --prepend_protocol(const gchar *url) --{ -- if (url && *url == '/') -- return g_strconcat("file://", url, NULL); -- return g_strdup(url); --} -- -- - int - koji_stuff_prepare(struct KojiMergedReposStuff **koji_stuff_ptr, - struct CmdOptions *cmd_options, -@@ -820,9 +809,7 @@ add_package(cr_Package *pkg, - if (!list) { - list = g_slist_prepend(list, pkg); - if ((!pkg->location_base || *pkg->location_base == '\0') && repopath) { -- _cleanup_free_ gchar *repopath_with_protocol = NULL; -- repopath_with_protocol = prepend_protocol(repopath); -- pkg->location_base = cr_safe_string_chunk_insert(pkg->chunk, repopath_with_protocol); -+ pkg->location_base = cr_safe_string_chunk_insert(pkg->chunk, repopath); - } - g_hash_table_insert (merged, (gpointer) pkg->name, (gpointer) list); - return 1; -@@ -1039,7 +1026,7 @@ merge_repos(GHashTable *merged, - // Koji-mergerepos specific behaviour ----------- - if (koji_stuff && koji_stuff->pkgorigins) { - _cleanup_free_ gchar *nvra = cr_package_nvra(pkg); -- _cleanup_free_ gchar *url = prepend_protocol(ml->original_url); -+ _cleanup_free_ gchar *url = cr_prepend_protocol(ml->original_url); - - cr_printf(NULL, - koji_stuff->pkgorigins, -diff --git a/src/xml_dump.c b/src/xml_dump.c -index 3fbb422..7a93231 100644 ---- a/src/xml_dump.c -+++ b/src/xml_dump.c -@@ -53,6 +53,14 @@ gboolean cr_hascontrollchars(const unsigned char *str) - return FALSE; - } - -+gchar * -+cr_prepend_protocol(const gchar *url) -+{ -+ if (url && *url == '/') -+ return g_strconcat("file://", url, NULL); -+ return g_strdup(url); -+} -+ - void - cr_latin1_to_utf8(const unsigned char *in, unsigned char *out) - { -diff --git a/src/xml_dump.h b/src/xml_dump.h -index 8bb11ed..4289fc2 100644 ---- a/src/xml_dump.h -+++ b/src/xml_dump.h -@@ -167,6 +167,14 @@ void cr_latin1_to_utf8(const unsigned char *in, - */ - gboolean cr_hascontrollchars(const unsigned char *str); - -+/** -+ * Prepend protocol if necessary -+ * -+ * @param url input url -+ * @return output string, must be freed -+ */ -+gchar *cr_prepend_protocol(const gchar *url); -+ - /** @} */ - - #ifdef __cplusplus -diff --git a/src/xml_dump_primary.c b/src/xml_dump_primary.c -index 5695e06..1f0292b 100644 ---- a/src/xml_dump_primary.c -+++ b/src/xml_dump_primary.c -@@ -30,7 +30,6 @@ - - #define ERR_DOMAIN CREATEREPO_C_ERROR - -- - typedef enum { - PCO_TYPE_PROVIDES, - PCO_TYPE_CONFLICTS, -@@ -279,9 +278,12 @@ cr_xml_dump_primary_base_items(xmlNodePtr root, cr_Package *package) - - // Write location attribute base - if (package->location_base && package->location_base[0] != '\0') { -+ gchar *location_base_with_protocol = NULL; -+ location_base_with_protocol = cr_prepend_protocol(package->location_base); - cr_xmlNewProp(location, - BAD_CAST "xml:base", -- BAD_CAST package->location_base); -+ BAD_CAST location_base_with_protocol); -+ g_free(location_base_with_protocol); - } - - // Write location attribute href --- -libgit2 0.27.8 - diff --git a/SOURCES/0001-Libmagic-to-follow-symlinks-RhBug1776399.patch b/SOURCES/0001-Libmagic-to-follow-symlinks-RhBug1776399.patch new file mode 100644 index 0000000..5221458 --- /dev/null +++ b/SOURCES/0001-Libmagic-to-follow-symlinks-RhBug1776399.patch @@ -0,0 +1,60 @@ +From 566311457542d08f48507b0ab7bd68cb848594e9 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Fri, 29 Nov 2019 09:47:29 +0100 +Subject: [PATCH 1/2] Libmagic to follow symlinks (RhBug:1776399) + +If the input metadata file for modifyrepo_c was a symlink the +program failed to detect compression type. This patch instructs +libmagic to follow the symlinks when guessing the mime type. + +Let modules.yaml be a symlink: + +$ modifyrepo_c ./modules.yaml ./repodata +Cannot open ./modules.yaml: Cannot detect compression type + +https://bugzilla.redhat.com/show_bug.cgi?id=1776399 +--- + src/compression_wrapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compression_wrapper.c b/src/compression_wrapper.c +index d04ab24..6fdb8ea 100644 +--- a/src/compression_wrapper.c ++++ b/src/compression_wrapper.c +@@ -166,7 +166,7 @@ cr_detect_compression(const char *filename, GError **err) + + // No success? Let's get hardcore... (Use magic bytes) + +- magic_t myt = magic_open(MAGIC_MIME); ++ magic_t myt = magic_open(MAGIC_MIME | MAGIC_SYMLINK); + if (myt == NULL) { + g_set_error(err, ERR_DOMAIN, CRE_MAGIC, + "magic_open() failed: Cannot allocate the magic cookie"); + +From b1b849c3bd63424760152981f96031ef578d752c Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Fri, 29 Nov 2019 10:53:25 +0100 +Subject: [PATCH 2/2] Add shortcut to detect *.yaml files as not compressed + +--- + src/compression_wrapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compression_wrapper.c b/src/compression_wrapper.c +index 6fdb8ea..56d1dc5 100644 +--- a/src/compression_wrapper.c ++++ b/src/compression_wrapper.c +@@ -158,12 +158,12 @@ cr_detect_compression(const char *filename, GError **err) + return CR_CW_ZCK_COMPRESSION; + } else if (g_str_has_suffix(filename, ".xml") || + g_str_has_suffix(filename, ".tar") || ++ g_str_has_suffix(filename, ".yaml") || + g_str_has_suffix(filename, ".sqlite")) + { + return CR_CW_NO_COMPRESSION; + } + +- + // No success? Let's get hardcore... (Use magic bytes) + + magic_t myt = magic_open(MAGIC_MIME | MAGIC_SYMLINK); diff --git a/SOURCES/0002-Add-reboot_suggested-to-UpdateRecord-RhBug1772466.patch b/SOURCES/0002-Add-reboot_suggested-to-UpdateRecord-RhBug1772466.patch new file mode 100644 index 0000000..ed4f49b --- /dev/null +++ b/SOURCES/0002-Add-reboot_suggested-to-UpdateRecord-RhBug1772466.patch @@ -0,0 +1,458 @@ +From af9c8b4575749c3d03afe6c704060661622199bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Tue, 3 Dec 2019 09:21:27 +0100 +Subject: [PATCH 1/3] Add reboot_suggested field to UpdateRecord + (RhBug:1772466) + +https://bugzilla.redhat.com/show_bug.cgi?id=1772466 +--- + src/python/updaterecord-py.c | 35 +++++++++++++++++++++++++++++++++++ + src/updateinfo.c | 1 + + src/updateinfo.h | 1 + + src/xml_dump_updateinfo.c | 3 +++ + src/xml_parser_updateinfo.c | 9 +++++++++ + 5 files changed, 49 insertions(+) + +diff --git a/src/python/updaterecord-py.c b/src/python/updaterecord-py.c +index 4f41019..b74bcb8 100644 +--- a/src/python/updaterecord-py.c ++++ b/src/python/updaterecord-py.c +@@ -248,6 +248,16 @@ static ListConvertor list_convertors[] = { + + #define OFFSET(member) (void *) offsetof(cr_UpdateRecord, member) + ++static PyObject * ++get_int(_UpdateRecordObject *self, void *member_offset) ++{ ++ if (check_UpdateRecordStatus(self)) ++ return NULL; ++ cr_UpdateRecord *rec = self->record; ++ gint64 val = *((int *) ((size_t) rec + (size_t) member_offset)); ++ return PyLong_FromLongLong((long long) val); ++} ++ + static PyObject * + get_str(_UpdateRecordObject *self, void *member_offset) + { +@@ -311,6 +321,29 @@ get_list(_UpdateRecordObject *self, void *conv) + return list; + } + ++static int ++set_int(_UpdateRecordObject *self, PyObject *value, void *member_offset) ++{ ++ long val; ++ if (check_UpdateRecordStatus(self)) ++ return -1; ++ if (PyLong_Check(value)) { ++ val = PyLong_AsLong(value); ++ } else if (PyFloat_Check(value)) { ++ val = (long long) PyFloat_AS_DOUBLE(value); ++#if PY_MAJOR_VERSION < 3 ++ } else if (PyInt_Check(value)) { ++ val = PyInt_AS_LONG(value); ++#endif ++ } else { ++ PyErr_SetString(PyExc_TypeError, "Number expected!"); ++ return -1; ++ } ++ cr_UpdateRecord *rec = self->record; ++ *((int *) ((size_t) rec + (size_t) member_offset)) = (int) val; ++ return 0; ++} ++ + static int + set_str(_UpdateRecordObject *self, PyObject *value, void *member_offset) + { +@@ -388,6 +421,8 @@ static PyGetSetDef updaterecord_getsetters[] = { + "List of UpdateReferences", &(list_convertors[0])}, + {"collections", (getter)get_list, (setter)NULL, + "List of UpdateCollections", &(list_convertors[1])}, ++ {"reboot_suggested", (getter)get_int, (setter)set_int, ++ "Suggested reboot", OFFSET(reboot_suggested)}, + {NULL, NULL, NULL, NULL, NULL} /* sentinel */ + }; + +diff --git a/src/updateinfo.c b/src/updateinfo.c +index cdc4747..bef06f2 100644 +--- a/src/updateinfo.c ++++ b/src/updateinfo.c +@@ -249,6 +249,7 @@ cr_updaterecord_copy(const cr_UpdateRecord *orig) + rec->summary = cr_safe_string_chunk_insert(rec->chunk, orig->summary); + rec->description = cr_safe_string_chunk_insert(rec->chunk, orig->description); + rec->solution = cr_safe_string_chunk_insert(rec->chunk, orig->solution); ++ rec->reboot_suggested = orig->reboot_suggested; + + if (orig->references) { + GSList *newlist = NULL; +diff --git a/src/updateinfo.h b/src/updateinfo.h +index 38883e0..2a69384 100644 +--- a/src/updateinfo.h ++++ b/src/updateinfo.h +@@ -92,6 +92,7 @@ typedef struct { + gchar *summary; /*!< Short summary */ + gchar *description; /*!< Update description */ + gchar *solution; /*!< Solution */ ++ gboolean reboot_suggested; /*!< Reboot suggested */ + + GSList *references; /*!< List of cr_UpdateReference */ + GSList *collections;/*!< List of cr_UpdateCollection */ +diff --git a/src/xml_dump_updateinfo.c b/src/xml_dump_updateinfo.c +index fafe686..0beed96 100644 +--- a/src/xml_dump_updateinfo.c ++++ b/src/xml_dump_updateinfo.c +@@ -165,6 +165,9 @@ cr_xml_dump_updateinforecord_internal(xmlNodePtr root, cr_UpdateRecord *rec) + cr_xmlNewTextChild_c(update, NULL, BAD_CAST "description", BAD_CAST rec->description); + cr_xmlNewTextChild_c(update, NULL, BAD_CAST "solution", BAD_CAST rec->solution); + ++ if (rec->reboot_suggested) ++ xmlNewChild(update, NULL, BAD_CAST "reboot_suggested", NULL); ++ + // References + cr_xml_dump_updateinforecord_references(update, rec->references); + +diff --git a/src/xml_parser_updateinfo.c b/src/xml_parser_updateinfo.c +index 5a2715a..3e458ec 100644 +--- a/src/xml_parser_updateinfo.c ++++ b/src/xml_parser_updateinfo.c +@@ -58,6 +58,7 @@ typedef enum { + STATE_PACKAGE, + STATE_FILENAME, + STATE_SUM, ++ STATE_UPDATERECORD_REBOOTSUGGESTED, + STATE_REBOOTSUGGESTED, + STATE_RESTARTSUGGESTED, // Not implemented + STATE_RELOGINSUGGESTED, // Not implemented +@@ -86,6 +87,7 @@ static cr_StatesSwitch stateswitches[] = { + { STATE_UPDATE, "message", STATE_MESSAGE, 1 }, // NI + { STATE_UPDATE, "references", STATE_REFERENCES, 0 }, + { STATE_UPDATE, "pkglist", STATE_PKGLIST, 0 }, ++ { STATE_UPDATE, "reboot_suggested", STATE_UPDATERECORD_REBOOTSUGGESTED,0 }, + { STATE_REFERENCES, "reference", STATE_REFERENCE, 0 }, + { STATE_PKGLIST, "collection", STATE_COLLECTION, 0 }, + { STATE_COLLECTION, "package", STATE_PACKAGE, 0 }, +@@ -360,6 +362,12 @@ cr_start_handler(void *pdata, const char *element, const char **attr) + package->sum_type = cr_checksum_type(val); + break; + ++ case STATE_UPDATERECORD_REBOOTSUGGESTED: ++ assert(pd->updateinfo); ++ assert(pd->updaterecord); ++ rec->reboot_suggested = TRUE; ++ break; ++ + case STATE_REBOOTSUGGESTED: + assert(pd->updateinfo); + assert(pd->updaterecord); +@@ -406,6 +414,7 @@ cr_end_handler(void *pdata, G_GNUC_UNUSED const char *element) + case STATE_MODULE: + case STATE_PKGLIST: + case STATE_REBOOTSUGGESTED: ++ case STATE_UPDATERECORD_REBOOTSUGGESTED: + // All elements with no text data and without need of any + // post processing should go here + break; +-- +2.24.1 + + +From d4fb876b4475c7ede4b49219229638bf32e9574d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Tue, 3 Dec 2019 09:32:18 +0100 +Subject: [PATCH 2/3] Extend unit tests with reboot_suggested for UpdateRecord + +--- + tests/python/tests/test_updateinfo.py | 6 ++++++ + tests/python/tests/test_updaterecord.py | 5 +++++ + tests/test_xml_parser_updateinfo.c | 8 ++++++++ + tests/testdata/updateinfo_files/updateinfo_01.xml | 1 + + tests/testdata/updateinfo_files/updateinfo_03.xml | 2 ++ + 5 files changed, 22 insertions(+) + +diff --git a/tests/python/tests/test_updateinfo.py b/tests/python/tests/test_updateinfo.py +index 727b707..7feaae9 100644 +--- a/tests/python/tests/test_updateinfo.py ++++ b/tests/python/tests/test_updateinfo.py +@@ -36,6 +36,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + rec.summary = "summary" + rec.description = "description" + rec.solution = "solution" ++ rec.reboot_suggested = True + + ui.append(rec) + +@@ -57,6 +58,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + self.assertEqual(rec.summary, "summary") + self.assertEqual(rec.description, "description") + self.assertEqual(rec.solution, "solution") ++ self.assertEqual(rec.reboot_suggested, True) + self.assertEqual(len(rec.references), 0) + self.assertEqual(len(rec.collections), 0) + +@@ -92,6 +94,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + rec.summary = "summary" + rec.description = "description" + rec.solution = "solution" ++ rec.reboot_suggested = True + + ui.append(rec) + xml = ui.xml_dump() +@@ -111,6 +114,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + summary + description + solution ++ + + + +@@ -349,6 +353,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + rec.summary = "summary" + rec.description = "description" + rec.solution = "solution" ++ rec.reboot_suggested = True + rec.append_collection(col) + rec.append_reference(ref) + +@@ -372,6 +377,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + summary + description + solution ++ + + + +diff --git a/tests/python/tests/test_updaterecord.py b/tests/python/tests/test_updaterecord.py +index 6777f04..7a1a191 100644 +--- a/tests/python/tests/test_updaterecord.py ++++ b/tests/python/tests/test_updaterecord.py +@@ -32,6 +32,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + self.assertEqual(rec.severity, None) + self.assertEqual(rec.summary, None) + self.assertEqual(rec.description, None) ++ self.assertEqual(rec.reboot_suggested, 0) + self.assertEqual(rec.solution, None) + self.assertEqual(rec.references, []) + self.assertEqual(rec.collections, []) +@@ -60,6 +61,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + rec.severity = "severity" + rec.summary = "summary" + rec.description = "description" ++ rec.reboot_suggested = True + rec.solution = "solution" + rec.append_reference(ref) + rec.append_collection(col) +@@ -77,6 +79,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + self.assertEqual(rec.pushcount, "pushcount") + self.assertEqual(rec.severity, "severity") + self.assertEqual(rec.summary, "summary") ++ self.assertEqual(rec.reboot_suggested, True) + self.assertEqual(rec.description, "description") + self.assertEqual(rec.solution, "solution") + self.assertEqual(len(rec.references), 1) +@@ -115,6 +118,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + rec.summary = "summary" + rec.description = "description" + rec.solution = "solution" ++ rec.reboot_suggested = True + + xml = cr.xml_dump_updaterecord(rec) + self.assertEqual(xml, +@@ -130,6 +134,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + summary + description + solution ++ + + + +diff --git a/tests/test_xml_parser_updateinfo.c b/tests/test_xml_parser_updateinfo.c +index 976922e..07ef50e 100644 +--- a/tests/test_xml_parser_updateinfo.c ++++ b/tests/test_xml_parser_updateinfo.c +@@ -76,6 +76,7 @@ test_cr_xml_parse_updateinfo_01(void) + g_assert_cmpstr(update->summary, ==, "summary_1"); + g_assert_cmpstr(update->description, ==, "description_1"); + g_assert_cmpstr(update->solution, ==, "solution_1"); ++ g_assert(update->reboot_suggested); + + g_assert_cmpint(g_slist_length(update->references), ==, 1); + ref = update->references->data; +@@ -137,6 +138,7 @@ test_cr_xml_parse_updateinfo_02(void) + g_assert(!update->pushcount); + g_assert(!update->severity); + g_assert(!update->summary); ++ g_assert(!update->reboot_suggested); + g_assert(!update->description); + g_assert(!update->solution); + +@@ -186,6 +188,10 @@ test_cr_xml_parse_updateinfo_03(void) + g_assert_cmpint(ret, ==, CRE_OK); + + g_assert_cmpint(g_slist_length(ui->updates), ==, 6); ++ ++ update = g_slist_nth_data(ui->updates, 2); ++ g_assert(!update->reboot_suggested); ++ + update = g_slist_nth_data(ui->updates, 3); + + g_assert_cmpstr(update->from, ==, "errata@redhat.com"); +@@ -195,6 +201,7 @@ test_cr_xml_parse_updateinfo_03(void) + g_assert_cmpstr(update->id, ==, "RHEA-2012:0058"); + g_assert_cmpstr(update->title, ==, "Gorilla_Erratum"); + g_assert_cmpstr(update->description, ==, "Gorilla_Erratum"); ++ g_assert(update->reboot_suggested); + + update = g_slist_nth_data(ui->updates, 4); + +@@ -204,6 +211,7 @@ test_cr_xml_parse_updateinfo_03(void) + g_assert_cmpstr(update->issued_date, ==, "2018-01-27 16:08:09"); + g_assert_cmpstr(update->updated_date, ==, "2018-07-20 06:00:01 UTC"); + g_assert_cmpstr(update->release, ==, "1"); ++ g_assert(update->reboot_suggested); + + g_assert_cmpint(g_slist_length(update->references), ==, 0); + +diff --git a/tests/testdata/updateinfo_files/updateinfo_01.xml b/tests/testdata/updateinfo_files/updateinfo_01.xml +index b757ef8..415140e 100644 +--- a/tests/testdata/updateinfo_files/updateinfo_01.xml ++++ b/tests/testdata/updateinfo_files/updateinfo_01.xml +@@ -12,6 +12,7 @@ + summary_1 + description_1 + solution_1 ++ True + + + +diff --git a/tests/testdata/updateinfo_files/updateinfo_03.xml b/tests/testdata/updateinfo_files/updateinfo_03.xml +index ddbd99b..39dfbef 100644 +--- a/tests/testdata/updateinfo_files/updateinfo_03.xml ++++ b/tests/testdata/updateinfo_files/updateinfo_03.xml +@@ -70,6 +70,7 @@ + + + Gorilla_Erratum ++ True + + + 1 +@@ -87,6 +88,7 @@ + + + Duck_Kangaro_Erratum description ++ + + + coll_name1 +-- +2.24.1 + + +From c1ec192d14d751eed298ffff13fbbc76917d0b0e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Thu, 9 Jan 2020 08:52:22 +0100 +Subject: [PATCH 3/3] Switch updateinfo to explicitly include bool values + (RhBug:1772466) + +Elements and both were previously +outputed just as an empty element which meant they are true, this patch +changes it to explicitly output: +True. + +However we still don't output False values, in that case the element is +simply omitted. + +https://bugzilla.redhat.com/show_bug.cgi?id=1772466 +--- + src/xml_dump_updateinfo.c | 4 ++-- + tests/python/tests/test_updateinfo.py | 10 +++++----- + tests/python/tests/test_updaterecord.py | 2 +- + 3 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/src/xml_dump_updateinfo.c b/src/xml_dump_updateinfo.c +index 0beed96..6974285 100644 +--- a/src/xml_dump_updateinfo.c ++++ b/src/xml_dump_updateinfo.c +@@ -61,7 +61,7 @@ cr_xml_dump_updatecollectionpackages(xmlNodePtr collection, GSList *packages) + } + + if (pkg->reboot_suggested) +- xmlNewChild(package, NULL, BAD_CAST "reboot_suggested", NULL); ++ xmlNewChild(package, NULL, BAD_CAST "reboot_suggested", "True"); + } + } + +@@ -166,7 +166,7 @@ cr_xml_dump_updateinforecord_internal(xmlNodePtr root, cr_UpdateRecord *rec) + cr_xmlNewTextChild_c(update, NULL, BAD_CAST "solution", BAD_CAST rec->solution); + + if (rec->reboot_suggested) +- xmlNewChild(update, NULL, BAD_CAST "reboot_suggested", NULL); ++ xmlNewChild(update, NULL, BAD_CAST "reboot_suggested", "True"); + + // References + cr_xml_dump_updateinforecord_references(update, rec->references); +diff --git a/tests/python/tests/test_updateinfo.py b/tests/python/tests/test_updateinfo.py +index 7feaae9..f5becfe 100644 +--- a/tests/python/tests/test_updateinfo.py ++++ b/tests/python/tests/test_updateinfo.py +@@ -114,7 +114,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + summary + description + solution +- ++ True + + + +@@ -207,7 +207,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + + foo.rpm + abcdef +- ++ True + + + +@@ -293,7 +293,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + + foo.rpm + abcdef +- ++ True + + + +@@ -377,7 +377,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + summary + description + solution +- ++ True + + + +@@ -388,7 +388,7 @@ class TestCaseUpdateInfo(unittest.TestCase): + + foo.rpm + abcdef +- ++ True + + + +diff --git a/tests/python/tests/test_updaterecord.py b/tests/python/tests/test_updaterecord.py +index 7a1a191..e8bc789 100644 +--- a/tests/python/tests/test_updaterecord.py ++++ b/tests/python/tests/test_updaterecord.py +@@ -134,7 +134,7 @@ class TestCaseUpdateRecord(unittest.TestCase): + summary + description + solution +- ++ True + + + +-- +2.24.1 + diff --git a/SOURCES/0002-modifyrepo_c-Prevent-doubling-of-compression-testgzgz-RhBug1639287.patch b/SOURCES/0002-modifyrepo_c-Prevent-doubling-of-compression-testgzgz-RhBug1639287.patch deleted file mode 100644 index 97a5599..0000000 --- a/SOURCES/0002-modifyrepo_c-Prevent-doubling-of-compression-testgzgz-RhBug1639287.patch +++ /dev/null @@ -1,130 +0,0 @@ -From a535b3f25e4391f23d1cee46028827285e221de3 Mon Sep 17 00:00:00 2001 -From: Aleš Matěj -Date: Tue, 18 Jun 2019 13:49:27 +0200 -Subject: [PATCH] modifyrepo_c: Prevent doubling of compression (test.gz.gz) (RhBug:1639287) - ---- - src/compression_wrapper.c | 3 ++- - src/misc.c | 22 +++++++--------------- - src/modifyrepo_shared.c | 22 +++++++++++++++++++++- - 3 files changed, 30 insertions(+), 17 deletions(-) - -diff --git a/src/compression_wrapper.c b/src/compression_wrapper.c -index adc2f39..efb075c 100644 ---- a/src/compression_wrapper.c -+++ b/src/compression_wrapper.c -@@ -148,7 +148,8 @@ cr_detect_compression(const char *filename, GError **err) - } else if (g_str_has_suffix(filename, ".xz")) - { - return CR_CW_XZ_COMPRESSION; -- } else if (g_str_has_suffix(filename, ".xml")) -+ } else if (g_str_has_suffix(filename, ".xml") || -+ g_str_has_suffix(filename, ".sqlite")) - { - return CR_CW_NO_COMPRESSION; - } -diff --git a/src/misc.c b/src/misc.c -index 9937480..c5ccd12 100644 ---- a/src/misc.c -+++ b/src/misc.c -@@ -437,7 +437,7 @@ cr_compress_file_with_stat(const char *src, - int ret = CRE_OK; - int readed; - char buf[BUFFER_SIZE]; -- FILE *orig = NULL; -+ CR_FILE *orig = NULL; - CR_FILE *new = NULL; - gchar *dst = (gchar *) in_dst; - GError *tmp_err = NULL; -@@ -466,7 +466,7 @@ cr_compress_file_with_stat(const char *src, - NULL); - } - -- orig = fopen(src, "rb"); -+ orig = cr_open(src, CR_CW_MODE_READ, CR_CW_AUTO_DETECT_COMPRESSION, &tmp_err); - if (orig == NULL) { - g_debug("%s: Cannot open source file %s (%s)", __func__, src, - g_strerror(errno)); -@@ -484,21 +484,13 @@ cr_compress_file_with_stat(const char *src, - goto compress_file_cleanup; - } - -- while ((readed = fread(buf, 1, BUFFER_SIZE, orig)) > 0) { -- if (readed != BUFFER_SIZE && ferror(orig)) { -- g_debug("%s: Error while copy %s -> %s (%s)", __func__, src, -- dst, g_strerror(errno)); -- g_set_error(err, ERR_DOMAIN, CRE_IO, -- "Error while read %s: %s", src, g_strerror(errno)); -- ret = CRE_IO; -- goto compress_file_cleanup; -- } -- -- cr_write(new, buf, readed, &tmp_err); -+ while ((readed = cr_read(orig, buf, BUFFER_SIZE, &tmp_err)) > 0) { -+ if (!tmp_err) -+ cr_write(new, buf, readed, &tmp_err); - if (tmp_err) { - g_debug("%s: Error while copy %s -> %s", __func__, src, dst); - g_propagate_prefixed_error(err, tmp_err, -- "Error while read %s: ", dst); -+ "Error while copy to %s: ", dst); - ret = CRE_IO; - goto compress_file_cleanup; - } -@@ -510,7 +502,7 @@ compress_file_cleanup: - g_free(dst); - - if (orig) -- fclose(orig); -+ cr_close(orig, NULL); - - if (new) - cr_close(new, NULL); -diff --git a/src/modifyrepo_shared.c b/src/modifyrepo_shared.c -index 805c894..91e56e8 100644 ---- a/src/modifyrepo_shared.c -+++ b/src/modifyrepo_shared.c -@@ -50,6 +50,23 @@ cr_modifyrepotask_free(cr_ModifyRepoTask *task) - g_free(task); - } - -+gchar * -+remove_compression_suffix_if_present(gchar* name, GError **err) -+{ -+ cr_CompressionType src_fn_com_type = cr_detect_compression(name, err); -+ if (src_fn_com_type != CR_CW_NO_COMPRESSION && src_fn_com_type != CR_CW_UNKNOWN_COMPRESSION){ -+ const gchar *src_suffix = cr_compression_suffix(src_fn_com_type); -+ if (src_suffix){ -+ if (g_str_has_suffix(name, src_suffix)){ -+ int name_len = strlen(name); -+ int suffix_len = strlen(src_suffix); -+ return g_strndup(name, name_len - suffix_len); -+ } -+ } -+ } -+ return g_strdup(name); -+} -+ - gboolean - cr_modifyrepo(GSList *modifyrepotasks, gchar *repopath, GError **err) - { -@@ -192,12 +209,15 @@ cr_modifyrepo(GSList *modifyrepotasks, gchar *repopath, GError **err) - suffix = cr_compression_suffix(compress_type); - } - -+ char* sufixless_src_fn = remove_compression_suffix_if_present(task->path, err); -+ - // Prepare dst filename - Get basename - _cleanup_free_ gchar *filename = NULL; - if (task->new_name) - filename = g_path_get_basename(task->new_name); - else -- filename = g_path_get_basename(src_fn); -+ filename = g_path_get_basename(sufixless_src_fn); -+ g_free(sufixless_src_fn); - - // Prepare dst filename - Add suffix - if (suffix) { --- -libgit2 0.27.8 - diff --git a/SOURCES/0003-Correct-pkg-count-in-headers-if-there-were-invalid-pkgs-RhBug1596211.patch b/SOURCES/0003-Correct-pkg-count-in-headers-if-there-were-invalid-pkgs-RhBug1596211.patch deleted file mode 100644 index e546c4b..0000000 --- a/SOURCES/0003-Correct-pkg-count-in-headers-if-there-were-invalid-pkgs-RhBug1596211.patch +++ /dev/null @@ -1,466 +0,0 @@ -From dfe7218f07ffa70b73c51c71b0f051be926b6d92 Mon Sep 17 00:00:00 2001 -From: Aleš Matěj -Date: Tue, 14 May 2019 16:48:13 +0200 -Subject: [PATCH] Correct pkg count in headers if there were invalid pkgs (RhBug:1596211) - ---- - src/createrepo_c.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- - src/dumper_thread.c | 4 +++- - src/dumper_thread.h | 3 ++- - src/threads.c | 23 +++++++++++++++++++++++ - src/threads.h | 5 +++++ - src/xml_file.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - src/xml_file.h | 15 +++++++++++++++ - 7 files changed, 260 insertions(+), 16 deletions(-) - -diff --git a/src/createrepo_c.c b/src/createrepo_c.c -index e16ae34..67c2752 100644 ---- a/src/createrepo_c.c -+++ b/src/createrepo_c.c -@@ -124,7 +124,7 @@ fill_pool(GThreadPool *pool, - struct CmdOptions *cmd_options, - GSList **current_pkglist, - FILE *output_pkg_list, -- long *package_count, -+ long *task_count, - int media_id) - { - GQueue queue = G_QUEUE_INIT; -@@ -259,13 +259,13 @@ fill_pool(GThreadPool *pool, - - // Push sorted tasks into the thread pool - while ((task = g_queue_pop_head(&queue)) != NULL) { -- task->id = *package_count; -+ task->id = *task_count; - task->media_id = media_id; - g_thread_pool_push(pool, task, NULL); -- ++*package_count; -+ ++*task_count; - } - -- return *package_count; -+ return *task_count; - } - - -@@ -321,6 +321,27 @@ prepare_cache_dir(struct CmdOptions *cmd_options, - return TRUE; - } - -+/** Check if task finished without error, if yes -+ * use content stats of the new file -+ * -+ * @param task Rewrite pkg count task -+ * @param filename Name of file with wrong package count -+ * @param exit_val If errors occured set createrepo_c exit value -+ * @param content_stat Content stats for filename -+ * -+ */ -+static void -+error_check_and_set_content_stat(cr_CompressionTask *task, char *filename, int *exit_val, cr_ContentStat **content_stat){ -+ if (task->err) { -+ g_critical("Cannot rewrite pkg count in %s: %s", -+ filename, task->err->message); -+ *exit_val = 2; -+ }else{ -+ cr_contentstat_free(*content_stat, NULL); -+ *content_stat = task->stat; -+ task->stat = NULL; -+ } -+} - - int - main(int argc, char **argv) -@@ -478,7 +499,7 @@ main(int argc, char **argv) - NULL); - g_debug("Thread pool ready"); - -- long package_count = 0; -+ long task_count = 0; - GSList *current_pkglist = NULL; - /* ^^^ List with basenames of files which will be processed */ - -@@ -490,26 +511,26 @@ main(int argc, char **argv) - cmd_options, - ¤t_pkglist, - output_pkg_list, -- &package_count, -+ &task_count, - media_id); - g_free(tmp_in_dir); - } - -- g_debug("Package count: %ld", package_count); -- g_message("Directory walk done - %ld packages", package_count); -+ g_debug("Package count: %ld", task_count); -+ g_message("Directory walk done - %ld packages", task_count); - - if (output_pkg_list) - fclose(output_pkg_list); - - - // Load old metadata if --update - cr_Metadata *old_metadata = NULL; - struct cr_MetadataLocation *old_metadata_location = NULL; - -- if (!package_count) -+ if (!task_count) - g_debug("No packages found - skipping metadata loading"); - -- if (package_count && cmd_options->update) { -+ if (task_count && cmd_options->update) { - int ret; - old_metadata = cr_metadata_new(CR_HT_KEY_FILENAME, 1, current_pkglist); - cr_metadata_set_dupaction(old_metadata, CR_HT_DUPACT_REMOVEALL); -@@ -741,9 +762,9 @@ main(int argc, char **argv) - - // Set number of packages - g_debug("Setting number of packages"); -- cr_xmlfile_set_num_of_pkgs(pri_cr_file, package_count, NULL); -- cr_xmlfile_set_num_of_pkgs(fil_cr_file, package_count, NULL); -- cr_xmlfile_set_num_of_pkgs(oth_cr_file, package_count, NULL); -+ cr_xmlfile_set_num_of_pkgs(pri_cr_file, task_count, NULL); -+ cr_xmlfile_set_num_of_pkgs(fil_cr_file, task_count, NULL); -+ cr_xmlfile_set_num_of_pkgs(oth_cr_file, task_count, NULL); - - // Open sqlite databases - gchar *pri_db_filename = NULL; -@@ -832,7 +853,8 @@ main(int argc, char **argv) - user_data.checksum_cachedir = cmd_options->checksum_cachedir; - user_data.skip_symlinks = cmd_options->skip_symlinks; - user_data.repodir_name_len = strlen(in_dir); -- user_data.package_count = package_count; -+ user_data.task_count = task_count; -+ user_data.package_count = 0; - user_data.skip_stat = cmd_options->skip_stat; - user_data.old_metadata = old_metadata; - user_data.mutex_pri = g_mutex_new(); -@@ -876,6 +898,59 @@ main(int argc, char **argv) - cr_xmlfile_close(fil_cr_file, NULL); - cr_xmlfile_close(oth_cr_file, NULL); - -+ -+ /* At the time of writing xml metadata headers we haven't yet parsed all -+ * the packages and we don't know whether there were some invalid ones, -+ * therefore we write the task count into the headers instead of the actual package count. -+ * If there actually were some invalid packages we have to correct this value -+ * that unfortunately means we have to decompress metadata files change package -+ * count value and compress them again. -+ */ -+ if (user_data.package_count != user_data.task_count){ -+ g_message("Warning: There were some invalid packages: we have to recompress other, filelists and primary xml metadata files in order to have correct package counts"); -+ -+ GThreadPool *rewrite_pkg_count_pool = g_thread_pool_new(cr_rewrite_pkg_count_thread, -+ &user_data, 3, FALSE, NULL); -+ -+ cr_CompressionTask *pri_rewrite_pkg_count_task; -+ cr_CompressionTask *fil_rewrite_pkg_count_task; -+ cr_CompressionTask *oth_rewrite_pkg_count_task; -+ -+ pri_rewrite_pkg_count_task = cr_compressiontask_new(pri_xml_filename, -+ NULL, -+ xml_compression, -+ cmd_options->repomd_checksum_type, -+ 1, -+ &tmp_err); -+ g_thread_pool_push(rewrite_pkg_count_pool, pri_rewrite_pkg_count_task, NULL); -+ -+ fil_rewrite_pkg_count_task = cr_compressiontask_new(fil_xml_filename, -+ NULL, -+ xml_compression, -+ cmd_options->repomd_checksum_type, -+ 1, -+ &tmp_err); -+ g_thread_pool_push(rewrite_pkg_count_pool, fil_rewrite_pkg_count_task, NULL); -+ -+ oth_rewrite_pkg_count_task = cr_compressiontask_new(oth_xml_filename, -+ NULL, -+ xml_compression, -+ cmd_options->repomd_checksum_type, -+ 1, -+ &tmp_err); -+ g_thread_pool_push(rewrite_pkg_count_pool, oth_rewrite_pkg_count_task, NULL); -+ -+ g_thread_pool_free(rewrite_pkg_count_pool, FALSE, TRUE); -+ -+ error_check_and_set_content_stat(pri_rewrite_pkg_count_task, pri_xml_filename, &exit_val, &pri_stat); -+ error_check_and_set_content_stat(fil_rewrite_pkg_count_task, fil_xml_filename, &exit_val, &fil_stat); -+ error_check_and_set_content_stat(oth_rewrite_pkg_count_task, oth_xml_filename, &exit_val, &oth_stat); -+ -+ cr_compressiontask_free(pri_rewrite_pkg_count_task, NULL); -+ cr_compressiontask_free(fil_rewrite_pkg_count_task, NULL); -+ cr_compressiontask_free(oth_rewrite_pkg_count_task, NULL); -+ } -+ - g_queue_free(user_data.buffer); - g_mutex_free(user_data.mutex_buffer); - g_cond_free(user_data.cond_pri); -diff --git a/src/dumper_thread.c b/src/dumper_thread.c -index fbaa5be..e282f96 100644 ---- a/src/dumper_thread.c -+++ b/src/dumper_thread.c -@@ -74,6 +74,8 @@ write_pkg(long id, - g_mutex_lock(udata->mutex_pri); - while (udata->id_pri != id) - g_cond_wait (udata->cond_pri, udata->mutex_pri); -+ -+ udata->package_count++; - ++udata->id_pri; - cr_xmlfile_add_chunk(udata->pri_f, (const char *) res.primary, &tmp_err); - if (tmp_err) { -@@ -476,7 +478,7 @@ cr_dumper_thread(gpointer data, gpointer user_data) - - if (g_queue_get_length(udata->buffer) < MAX_TASK_BUFFER_LEN - && udata->id_pri != task->id -- && udata->package_count > (task->id + 1)) -+ && udata->task_count > (task->id + 1)) - { - // If: - // * this isn't our turn -diff --git a/src/dumper_thread.h b/src/dumper_thread.h -index ed21053..4e18869 100644 ---- a/src/dumper_thread.h -+++ b/src/dumper_thread.h -@@ -61,7 +61,8 @@ struct UserData { - cr_ChecksumType checksum_type; // Constant representing selected checksum - const char *checksum_cachedir; // Dir with cached checksums - gboolean skip_symlinks; // Skip symlinks -- long package_count; // Total number of packages to process -+ long task_count; // Total number of task to process -+ long package_count; // Total number of packages processed - - // Update stuff - gboolean skip_stat; // Skip stat() while updating -diff --git a/src/threads.c b/src/threads.c -index aee07d1..844e900 100644 ---- a/src/threads.c -+++ b/src/threads.c -@@ -21,6 +21,7 @@ - #include "threads.h" - #include "error.h" - #include "misc.h" -+#include "dumper_thread.h" - - #define ERR_DOMAIN CREATEREPO_C_ERROR - -@@ -108,6 +109,28 @@ cr_compressing_thread(gpointer data, G_GNUC_UNUSED gpointer user_data) - } - } - -+void -+cr_rewrite_pkg_count_thread(gpointer data, gpointer user_data) -+{ -+ cr_CompressionTask *task = data; -+ struct UserData *ud = user_data; -+ GError *tmp_err = NULL; -+ -+ assert(task); -+ -+ cr_rewrite_header_package_count(task->src, -+ task->type, -+ ud->package_count, -+ ud->task_count, -+ task->stat, -+ &tmp_err); -+ -+ if (tmp_err) { -+ // Error encountered -+ g_propagate_error(&task->err, tmp_err); -+ } -+} -+ - /** Parallel Repomd Record Fill */ - - cr_RepomdRecordFillTask * -diff --git a/src/threads.h b/src/threads.h -index 2d554cd..19ba917 100644 ---- a/src/threads.h -+++ b/src/threads.h -@@ -150,6 +150,11 @@ cr_repomdrecordfilltask_free(cr_RepomdRecordFillTask *task, GError **err); - void - cr_repomd_record_fill_thread(gpointer data, gpointer user_data); - -+/** Function for GThread Pool. -+ */ -+void -+cr_rewrite_pkg_count_thread(gpointer data, gpointer user_data); -+ - /** @} */ - - #ifdef __cplusplus -diff --git a/src/xml_file.c b/src/xml_file.c -index 65fb945..1d670ae 100644 ---- a/src/xml_file.c -+++ b/src/xml_file.c -@@ -18,8 +18,10 @@ - */ - - #include -+#include - #include - #include "xml_file.h" -+#include - #include "error.h" - #include "xml_dump.h" - #include "compression_wrapper.h" -@@ -40,6 +42,9 @@ - #define XML_PRESTODELTA_HEADER XML_HEADER"\n" - #define XML_UPDATEINFO_HEADER XML_HEADER"\n" - -+#define XML_MAX_HEADER_SIZE 300 -+#define XML_RECOMPRESS_BUFFER_SIZE 8192 -+ - #define XML_PRIMARY_FOOTER "" - #define XML_FILELISTS_FOOTER "" - #define XML_OTHER_FOOTER "" -@@ -317,3 +322,121 @@ cr_xmlfile_close(cr_XmlFile *f, GError **err) - - return CRE_OK; - } -+ -+static int -+write_modified_header(int task_count, -+ int package_count, -+ cr_XmlFile *cr_file, -+ gchar *header_buf, -+ int header_len, -+ GError **err) -+{ -+ GError *tmp_err = NULL; -+ gchar *package_count_string; -+ gchar *task_count_string; -+ int bytes_written = 0; -+ int package_count_string_len = rasprintf(&package_count_string, "packages=\"%i\"", package_count); -+ int task_count_string_len = rasprintf(&task_count_string, "packages=\"%i\"", task_count); -+ -+ gchar *pointer_to_pkgs = strstr(header_buf, task_count_string); -+ if (!pointer_to_pkgs){ -+ g_free(package_count_string); -+ g_free(task_count_string); -+ return 0; -+ } -+ gchar *pointer_to_pkgs_end = pointer_to_pkgs + task_count_string_len; -+ -+ bytes_written += cr_write(cr_file->f, header_buf, pointer_to_pkgs - header_buf, &tmp_err); -+ if (!tmp_err) -+ bytes_written += cr_write(cr_file->f, package_count_string, package_count_string_len, &tmp_err); -+ if (!tmp_err) -+ bytes_written += cr_write(cr_file->f, pointer_to_pkgs_end, header_len - (pointer_to_pkgs_end - header_buf), &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while writing header part:"); -+ g_free(package_count_string); -+ g_free(task_count_string); -+ return 0; -+ } -+ g_free(package_count_string); -+ g_free(task_count_string); -+ return bytes_written; -+} -+ -+void -+cr_rewrite_header_package_count(gchar *original_filename, -+ cr_CompressionType xml_compression, -+ int package_count, -+ int task_count, -+ cr_ContentStat *file_stat, -+ GError **err) -+{ -+ GError *tmp_err = NULL; -+ CR_FILE *original_file = cr_open(original_filename, CR_CW_MODE_READ, CR_CW_AUTO_DETECT_COMPRESSION, &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while reopening for reading:"); -+ return; -+ } -+ -+ gchar *tmp_xml_filename = g_strconcat(original_filename, ".tmp", NULL); -+ cr_XmlFile *new_file = cr_xmlfile_sopen_primary(tmp_xml_filename, -+ xml_compression, -+ file_stat, -+ &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while opening for writing:"); -+ cr_close(original_file, NULL); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ -+ gchar header_buf[XML_MAX_HEADER_SIZE]; -+ int len_read = cr_read(original_file, header_buf, XML_MAX_HEADER_SIZE, &tmp_err); -+ if (!tmp_err) -+ write_modified_header(task_count, package_count, new_file, header_buf, len_read, &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while recompressing:"); -+ cr_xmlfile_close(new_file, NULL); -+ cr_close(original_file, NULL); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ //Copy the rest of the file -+ gchar copy_buf[XML_RECOMPRESS_BUFFER_SIZE]; -+ while(len_read) -+ { -+ len_read = cr_read(original_file, copy_buf, XML_RECOMPRESS_BUFFER_SIZE, &tmp_err); -+ if (!tmp_err) -+ cr_write(new_file->f, copy_buf, len_read, &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while recompressing:"); -+ cr_xmlfile_close(new_file, NULL); -+ cr_close(original_file, NULL); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ } -+ -+ new_file->header = 1; -+ new_file->footer = 1; -+ -+ cr_xmlfile_close(new_file, &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while writing:"); -+ cr_close(original_file, NULL); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ cr_close(original_file, &tmp_err); -+ if (tmp_err) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while writing:"); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ -+ if (g_rename(tmp_xml_filename, original_filename) == -1) { -+ g_propagate_prefixed_error(err, tmp_err, "Error encountered while renaming:"); -+ g_free(tmp_xml_filename); -+ return; -+ } -+ g_free(tmp_xml_filename); -+} -diff --git a/src/xml_file.h b/src/xml_file.h -index 96ef5e3..6ac4c97 100644 ---- a/src/xml_file.h -+++ b/src/xml_file.h -@@ -221,6 +221,21 @@ int cr_xmlfile_add_chunk(cr_XmlFile *f, const char *chunk, GError **err); - */ - int cr_xmlfile_close(cr_XmlFile *f, GError **err); - -+/** Rewrite package count field in repodata header in xml file. -+ * In order to do this we have to decompress and after the change -+ * compress the whole file again, so entirely new file is created. -+ * @param original_filename Current file with wrong value in header -+ * @param package_count Actual package count (desired value in header) -+ * @param task_count Task count (current value in header) -+ * @param file_stat cr_ContentStat for stats of the new file, it will be modified -+ * @param err **GError -+ */ -+void cr_rewrite_header_package_count(gchar *original_filename, -+ cr_CompressionType xml_compression, -+ int package_count, -+ int task_count, -+ cr_ContentStat *file_stat, -+ GError **err); - - /** @} */ - --- -libgit2 0.27.8 - diff --git a/SOURCES/0004-Add-support-for-modular-errata-RhBug1656584.patch b/SOURCES/0004-Add-support-for-modular-errata-RhBug1656584.patch deleted file mode 100644 index 3765350..0000000 --- a/SOURCES/0004-Add-support-for-modular-errata-RhBug1656584.patch +++ /dev/null @@ -1,1329 +0,0 @@ -From a48db44b73785b5d5fbe8ae827522695fa0fd9ce Mon Sep 17 00:00:00 2001 -From: Aleš Matěj -Date: Tue, 8 Jan 2019 15:44:55 +0100 -Subject: [PATCH] Add support for modular errata (RhBug:1656584) - ---- - src/python/CMakeLists.txt | 1 + - src/python/__init__.py | 3 +++ - src/python/createrepo_cmodule.c | 8 ++++++++ - src/python/updatecollection-py.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - src/python/updatecollectionmodule-py.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - src/python/updatecollectionmodule-py.h | 33 +++++++++++++++++++++++++++++++++ - src/updateinfo.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ - src/updateinfo.h | 24 ++++++++++++++++++++++++ - src/xml_dump_updateinfo.c | 20 ++++++++++++++++++++ - src/xml_parser_internal.h | 2 ++ - src/xml_parser_updateinfo.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - tests/fixtures.h | 1 + - tests/python/tests/test_updatecollection.py | 16 ++++++++++++++++ - tests/python/tests/test_updatecollectionmodule.py | 31 +++++++++++++++++++++++++++++++ - tests/python/tests/test_updateinfo.py | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - tests/test_xml_parser_updateinfo.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - tests/testdata/updateinfo_files/updateinfo_03.xml | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 17 files changed, 957 insertions(+) - create mode 100644 src/python/updatecollectionmodule-py.c - create mode 100644 src/python/updatecollectionmodule-py.h - create mode 100644 tests/python/tests/test_updatecollectionmodule.py - create mode 100644 tests/testdata/updateinfo_files/updateinfo_03.xml - -diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt -index 9f1ac64..ebf4d4c 100644 ---- a/src/python/CMakeLists.txt -+++ b/src/python/CMakeLists.txt -@@ -50,6 +50,7 @@ SET (createrepo_cmodule_SRCS - sqlite-py.c - typeconversion.c - updatecollection-py.c -+ updatecollectionmodule-py.c - updatecollectionpackage-py.c - updateinfo-py.c - updaterecord-py.c -diff --git a/src/python/__init__.py b/src/python/__init__.py -index 6c29e74..65d7f82 100644 ---- a/src/python/__init__.py -+++ b/src/python/__init__.py -@@ -206,6 +206,9 @@ class OtherSqlite(Sqlite): - - UpdateCollection = _createrepo_c.UpdateCollection - -+# UpdateCollectionModule class -+ -+UpdateCollectionModule = _createrepo_c.UpdateCollectionModule - - # UpdateCollectionPackage class - -diff --git a/src/python/createrepo_cmodule.c b/src/python/createrepo_cmodule.c -index fe4d2ad..9be5f46 100644 ---- a/src/python/createrepo_cmodule.c -+++ b/src/python/createrepo_cmodule.c -@@ -35,6 +35,7 @@ - #include "repomdrecord-py.h" - #include "sqlite-py.h" - #include "updatecollection-py.h" -+#include "updatecollectionmodule-py.h" - #include "updatecollectionpackage-py.h" - #include "updateinfo-py.h" - #include "updaterecord-py.h" -@@ -185,6 +186,13 @@ init_createrepo_c(void) - PyModule_AddObject(m, "UpdateCollection", - (PyObject *)&UpdateCollection_Type); - -+ /* _createrepo_c.UpdateCollectionModule */ -+ if (PyType_Ready(&UpdateCollectionModule_Type) < 0) -+ return FAILURE; -+ Py_INCREF(&UpdateCollectionModule_Type); -+ PyModule_AddObject(m, "UpdateCollectionModule", -+ (PyObject *)&UpdateCollectionModule_Type); -+ - /* _createrepo_c.UpdateCollectionPackage */ - if (PyType_Ready(&UpdateCollectionPackage_Type) < 0) - return FAILURE; -diff --git a/src/python/updatecollection-py.c b/src/python/updatecollection-py.c -index 3a791be..ca97657 100644 ---- a/src/python/updatecollection-py.c -+++ b/src/python/updatecollection-py.c -@@ -22,6 +22,7 @@ - #include - - #include "updatecollection-py.h" -+#include "updatecollectionmodule-py.h" - #include "updatecollectionpackage-py.h" - #include "exception-py.h" - #include "typeconversion.h" -@@ -188,6 +189,13 @@ typedef int (*ConversionToCheckFunc)(PyObject *); - typedef void *(*ConversionToFunc)(PyObject *, GStringChunk *); - - PyObject * -+PyObject_FromUpdateCollectionModule(cr_UpdateCollectionModule *module) -+{ -+ return Object_FromUpdateCollectionModule( -+ cr_updatecollectionmodule_copy(module)); -+} -+ -+PyObject * - PyObject_FromUpdateCollectionPackage(cr_UpdateCollectionPackage *pkg) - { - return Object_FromUpdateCollectionPackage( -@@ -249,6 +257,23 @@ get_list(_UpdateCollectionObject *self, void *conv) - return list; - } - -+static PyObject * -+get_module(_UpdateCollectionObject *self, void *member_offset) -+{ -+ if (check_UpdateCollectionStatus(self)) -+ return NULL; -+ -+ cr_UpdateCollection *collection = self->collection; -+ -+ cr_UpdateCollectionModule *module = *((cr_UpdateCollectionModule **) ((size_t) collection + (size_t) member_offset)); -+ if (module == NULL) -+ Py_RETURN_NONE; -+ -+ PyObject *py_module = PyObject_FromUpdateCollectionModule(module); -+ -+ return py_module; -+} -+ - static int - set_str(_UpdateCollectionObject *self, PyObject *value, void *member_offset) - { -@@ -265,11 +290,29 @@ set_str(_UpdateCollectionObject *self, PyObject *value, void *member_offset) - return 0; - } - -+static int -+set_module(_UpdateCollectionObject *self, PyObject *value, void *member_offset) -+{ -+ if (check_UpdateCollectionStatus(self)) -+ return -1; -+ if (!UpdateCollectionModuleObject_Check(value) && value != Py_None) { -+ PyErr_SetString(PyExc_TypeError, "Module or None expected!"); -+ return -1; -+ } -+ cr_UpdateCollectionModule *module = UpdateCollectionModule_FromPyObject(value); -+ cr_UpdateCollection *collection = self->collection; -+ *((cr_UpdateCollectionModule **) ((size_t) collection + (size_t) member_offset)) = module; -+ -+ return 0; -+} -+ - static PyGetSetDef updatecollection_getsetters[] = { - {"shortname", (getter)get_str, (setter)set_str, - "Short name", OFFSET(shortname)}, - {"name", (getter)get_str, (setter)set_str, - "Name of the collection", OFFSET(name)}, -+ {"module", (getter)get_module, (setter)set_module, -+ "Module information", OFFSET(module)}, - {"packages", (getter)get_list, (setter)NULL, - "List of packages", &(list_convertors[0])}, - {NULL, NULL, NULL, NULL, NULL} /* sentinel */ -diff --git a/src/python/updatecollectionmodule-py.c b/src/python/updatecollectionmodule-py.c -new file mode 100644 -index 0000000..20b2d99 ---- /dev/null -+++ b/src/python/updatecollectionmodule-py.c -@@ -0,0 +1,274 @@ -+/* createrepo_c - Library of routines for manipulation with repodata -+ * Copyright (C) 2013 Tomas Mlcoch -+ * -+ * 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 -+#include -+#include -+ -+#include "updatecollectionmodule-py.h" -+#include "exception-py.h" -+#include "typeconversion.h" -+#include "contentstat-py.h" -+ -+typedef struct { -+ PyObject_HEAD -+ cr_UpdateCollectionModule *module; -+} _UpdateCollectionModuleObject; -+ -+PyObject * -+Object_FromUpdateCollectionModule(cr_UpdateCollectionModule *mod) -+{ -+ PyObject *py_rec; -+ -+ if (!mod) { -+ PyErr_SetString(PyExc_ValueError, "Expected a cr_UpdateCollectionModule pointer not NULL."); -+ return NULL; -+ } -+ -+ py_rec = PyObject_CallObject((PyObject *) &UpdateCollectionModule_Type, NULL); -+ cr_updatecollectionmodule_free(((_UpdateCollectionModuleObject *)py_rec)->module); -+ ((_UpdateCollectionModuleObject *)py_rec)->module = mod; -+ -+ return py_rec; -+} -+ -+cr_UpdateCollectionModule * -+UpdateCollectionModule_FromPyObject(PyObject *o) -+{ -+ if (!UpdateCollectionModuleObject_Check(o)) { -+ PyErr_SetString(PyExc_TypeError, "Expected a UpdateCollectionModule object."); -+ return NULL; -+ } -+ return ((_UpdateCollectionModuleObject *)o)->module; -+} -+ -+static int -+check_UpdateCollectionModuleStatus(const _UpdateCollectionModuleObject *self) -+{ -+ assert(self != NULL); -+ assert(UpdateCollectionModuleObject_Check(self)); -+ if (self->module == NULL) { -+ PyErr_SetString(CrErr_Exception, "Improper createrepo_c UpdateCollectionModule object."); -+ return -1; -+ } -+ return 0; -+} -+ -+/* Function on the type */ -+ -+static PyObject * -+updatecollectionmodule_new(PyTypeObject *type, -+ G_GNUC_UNUSED PyObject *args, -+ G_GNUC_UNUSED PyObject *kwds) -+{ -+ _UpdateCollectionModuleObject *self = (_UpdateCollectionModuleObject *)type->tp_alloc(type, 0); -+ if (self) { -+ self->module = NULL; -+ } -+ return (PyObject *)self; -+} -+ -+PyDoc_STRVAR(updatecollectionmodule_init__doc__, -+".. method:: __init__()\n\n"); -+ -+static int -+updatecollectionmodule_init(_UpdateCollectionModuleObject *self, -+ G_GNUC_UNUSED PyObject *args, -+ G_GNUC_UNUSED PyObject *kwds) -+{ -+ /* Free all previous resources when reinitialization */ -+ if (self->module) -+ cr_updatecollectionmodule_free(self->module); -+ -+ /* Init */ -+ self->module = cr_updatecollectionmodule_new(); -+ if (self->module == NULL) { -+ PyErr_SetString(CrErr_Exception, "UpdateCollectionModule initialization failed"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void -+updatecollectionmodule_dealloc(_UpdateCollectionModuleObject *self) -+{ -+ if (self->module) -+ cr_updatecollectionmodule_free(self->module); -+ Py_TYPE(self)->tp_free(self); -+} -+ -+static PyObject * -+updatecollectionmodule_repr(G_GNUC_UNUSED _UpdateCollectionModuleObject *self) -+{ -+ return PyUnicode_FromFormat(""); -+} -+ -+/* UpdateCollectionModule methods */ -+ -+PyDoc_STRVAR(copy__doc__, -+"copy() -> UpdateCollectionModule\n\n" -+"Return copy of the UpdateCollectionModule object"); -+ -+static PyObject * -+copy_updatecollectionmodule(_UpdateCollectionModuleObject *self, -+ G_GNUC_UNUSED void *nothing) -+{ -+ if (check_UpdateCollectionModuleStatus(self)) -+ return NULL; -+ return Object_FromUpdateCollectionModule(cr_updatecollectionmodule_copy(self->module)); -+} -+ -+static struct PyMethodDef updatecollectionmodule_methods[] = { -+ {"copy", (PyCFunction)copy_updatecollectionmodule, METH_NOARGS, -+ copy__doc__}, -+ {NULL} /* sentinel */ -+}; -+ -+/* getsetters */ -+ -+#define OFFSET(member) (void *) offsetof(cr_UpdateCollectionModule, member) -+ -+static PyObject * -+get_str(_UpdateCollectionModuleObject *self, void *member_offset) -+{ -+ if (check_UpdateCollectionModuleStatus(self)) -+ return NULL; -+ cr_UpdateCollectionModule *module = self->module; -+ char *str = *((char **) ((size_t) module + (size_t) member_offset)); -+ if (str == NULL) -+ Py_RETURN_NONE; -+ return PyUnicode_FromString(str); -+} -+ -+static PyObject * -+get_uint(_UpdateCollectionModuleObject *self, void *member_offset) -+{ -+ if (check_UpdateCollectionModuleStatus(self)) -+ return NULL; -+ cr_UpdateCollectionModule *module = self->module; -+ guint64 val = *((guint64 *) ((size_t) module + (size_t) member_offset)); -+ return PyLong_FromUnsignedLongLong((guint64) val); -+} -+ -+static int -+set_str(_UpdateCollectionModuleObject *self, PyObject *value, void *member_offset) -+{ -+ if (check_UpdateCollectionModuleStatus(self)) -+ return -1; -+ if (!PyUnicode_Check(value) && !PyBytes_Check(value) && value != Py_None) { -+ PyErr_SetString(PyExc_TypeError, "Unicode, bytes, or None expected!"); -+ return -1; -+ } -+ -+ if (PyUnicode_Check(value)) { -+ value = PyUnicode_AsUTF8String(value); -+ } -+ -+ cr_UpdateCollectionModule *module = self->module; -+ char *str = cr_safe_string_chunk_insert(module->chunk, -+ PyObject_ToStrOrNull(value)); -+ -+ *((char **) ((size_t) module + (size_t) member_offset)) = str; -+ return 0; -+} -+ -+static int -+set_uint(_UpdateCollectionModuleObject *self, PyObject *value, void *member_offset) -+{ -+ if (check_UpdateCollectionModuleStatus(self)) -+ return -1; -+ guint64 val; -+ -+ if (PyLong_Check(value)) { -+ val = PyLong_AsUnsignedLongLong(value); -+ } else if (PyFloat_Check(value)) { -+ val = (guint64) PyFloat_AS_DOUBLE(value); -+#if PY_MAJOR_VERSION < 3 -+ } else if (PyInt_Check(value)) { -+ val = PyInt_AS_LONG(value); -+#endif -+ } else { -+ PyErr_SetString(PyExc_TypeError, "Number expected!"); -+ return -1; -+ } -+ -+ cr_UpdateCollectionModule *module = self->module; -+ *((guint64 *) ((size_t) module + (size_t) member_offset)) = (guint64) val; -+ return 0; -+} -+ -+static PyGetSetDef updatecollectionmodule_getsetters[] = { -+ {"name", (getter)get_str, (setter)set_str, -+ "Name", OFFSET(name)}, -+ {"stream", (getter)get_str, (setter)set_str, -+ "Stream", OFFSET(stream)}, -+ {"version", (getter)get_uint, (setter)set_uint, -+ "Version", OFFSET(version)}, -+ {"context", (getter)get_str, (setter)set_str, -+ "Context", OFFSET(context)}, -+ {"arch", (getter)get_str, (setter)set_str, -+ "Arch", OFFSET(arch)}, -+ {NULL, NULL, NULL, NULL, NULL} /* sentinel */ -+}; -+ -+/* Object */ -+ -+PyTypeObject UpdateCollectionModule_Type = { -+ PyVarObject_HEAD_INIT(NULL, 0) -+ "createrepo_c.UpdateCollectionModule", /* tp_name */ -+ sizeof(_UpdateCollectionModuleObject), /* tp_basicsize */ -+ 0, /* tp_itemsize */ -+ (destructor) updatecollectionmodule_dealloc, /* tp_dealloc */ -+ 0, /* tp_print */ -+ 0, /* tp_getattr */ -+ 0, /* tp_setattr */ -+ 0, /* tp_compare */ -+ (reprfunc) updatecollectionmodule_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|Py_TPFLAGS_BASETYPE, /* tp_flags */ -+ updatecollectionmodule_init__doc__, /* tp_doc */ -+ 0, /* tp_traverse */ -+ 0, /* tp_clear */ -+ 0, /* tp_richcompare */ -+ 0, /* tp_weaklistoffset */ -+ PyObject_SelfIter, /* tp_iter */ -+ 0, /* tp_iternext */ -+ updatecollectionmodule_methods, /* tp_methods */ -+ 0, /* tp_members */ -+ updatecollectionmodule_getsetters, /* tp_getset */ -+ 0, /* tp_base */ -+ 0, /* tp_dict */ -+ 0, /* tp_descr_get */ -+ 0, /* tp_descr_set */ -+ 0, /* tp_dictoffset */ -+ (initproc) updatecollectionmodule_init,/* tp_init */ -+ 0, /* tp_alloc */ -+ updatecollectionmodule_new, /* tp_new */ -+ 0, /* tp_free */ -+ 0, /* tp_is_gc */ -+}; -diff --git a/src/python/updatecollectionmodule-py.h b/src/python/updatecollectionmodule-py.h -new file mode 100644 -index 0000000..5847259 ---- /dev/null -+++ b/src/python/updatecollectionmodule-py.h -@@ -0,0 +1,33 @@ -+/* createrepo_c - Library of routines for manipulation with repodata -+ * Copyright (C) 2013 Tomas Mlcoch -+ * -+ * 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 CR_UPDATECOLLECTIONMODULE_PY_H -+#define CR_UPDATECOLLECTIONMODULE_PY_H -+ -+#include "src/createrepo_c.h" -+ -+extern PyTypeObject UpdateCollectionModule_Type; -+ -+#define UpdateCollectionModuleObject_Check(o) \ -+ PyObject_TypeCheck(o, &UpdateCollectionModule_Type) -+ -+PyObject *Object_FromUpdateCollectionModule(cr_UpdateCollectionModule *rec); -+cr_UpdateCollectionModule *UpdateCollectionModule_FromPyObject(PyObject *o); -+ -+#endif -diff --git a/src/updateinfo.c b/src/updateinfo.c -index 6e45229..cdc4747 100644 ---- a/src/updateinfo.c -+++ b/src/updateinfo.c -@@ -74,6 +74,46 @@ cr_updatecollectionpackage_free(cr_UpdateCollectionPackage *pkg) - - - /* -+ * cr_UpdateCollectionModule -+ */ -+ -+cr_UpdateCollectionModule * -+cr_updatecollectionmodule_new(void) -+{ -+ cr_UpdateCollectionModule *module = g_malloc0(sizeof(*module)); -+ module->chunk = g_string_chunk_new(0); -+ return module; -+} -+ -+cr_UpdateCollectionModule * -+cr_updatecollectionmodule_copy(const cr_UpdateCollectionModule *orig) -+{ -+ cr_UpdateCollectionModule *module; -+ -+ if (!orig) return NULL; -+ -+ module = cr_updatecollectionmodule_new(); -+ -+ module->name = cr_safe_string_chunk_insert(module->chunk, orig->name); -+ module->stream = cr_safe_string_chunk_insert(module->chunk, orig->stream); -+ module->version = orig->version; -+ module->context = cr_safe_string_chunk_insert(module->chunk, orig->context); -+ module->arch = cr_safe_string_chunk_insert(module->chunk, orig->arch); -+ -+ return module; -+} -+ -+void -+cr_updatecollectionmodule_free(cr_UpdateCollectionModule *module) -+{ -+ if (!module) -+ return; -+ g_string_chunk_free(module->chunk); -+ g_free(module); -+} -+ -+ -+/* - * cr_UpdateCollection - */ - -@@ -97,6 +137,10 @@ cr_updatecollection_copy(const cr_UpdateCollection *orig) - col->shortname = cr_safe_string_chunk_insert(col->chunk, orig->shortname); - col->name = cr_safe_string_chunk_insert(col->chunk, orig->name); - -+ if (orig->module) { -+ col->module = cr_updatecollectionmodule_copy(orig->module); -+ } -+ - if (orig->packages) { - GSList *newlist = NULL; - for (GSList *elem = orig->packages; elem; elem = g_slist_next(elem)) { -diff --git a/src/updateinfo.h b/src/updateinfo.h -index dbf7807..38883e0 100644 ---- a/src/updateinfo.h -+++ b/src/updateinfo.h -@@ -51,8 +51,19 @@ typedef struct { - } cr_UpdateCollectionPackage; - - typedef struct { -+ gchar *name; -+ gchar *stream; -+ guint64 version; -+ gchar *context; -+ gchar *arch; -+ -+ GStringChunk *chunk; -+} cr_UpdateCollectionModule; -+ -+typedef struct { - gchar *shortname; /*!< e.g. rhn-tools-rhel-x86_64-server-6.5.aus */ - gchar *name; /*!< e.g. RHN Tools for RHEL AUS (v. 6.5 for 64-bit x86_64) */ -+ cr_UpdateCollectionModule *module; - GSList *packages; /*!< List of cr_UpdateCollectionPackage */ - GStringChunk *chunk; - } cr_UpdateCollection; -@@ -106,6 +117,19 @@ void - cr_updatecollectionpackage_free(cr_UpdateCollectionPackage *pkg); - - /* -+ * cr_UpdateCollectionModule -+ */ -+ -+cr_UpdateCollectionModule * -+cr_updatecollectionmodule_new(void); -+ -+cr_UpdateCollectionModule * -+cr_updatecollectionmodule_copy(const cr_UpdateCollectionModule *orig); -+ -+void -+cr_updatecollectionmodule_free(cr_UpdateCollectionModule *pkg); -+ -+/* - * cr_UpdateCollection - */ - -diff --git a/src/xml_dump_updateinfo.c b/src/xml_dump_updateinfo.c -index 4fb5720..fafe686 100644 ---- a/src/xml_dump_updateinfo.c -+++ b/src/xml_dump_updateinfo.c -@@ -66,6 +66,24 @@ cr_xml_dump_updatecollectionpackages(xmlNodePtr collection, GSList *packages) - } - - void -+cr_xml_dump_updatecollectionmodule(xmlNodePtr collection, cr_UpdateCollectionModule *module) -+{ -+ if (!module) -+ return; -+ -+ xmlNodePtr xml_module; -+ xml_module = xmlNewChild(collection, NULL, BAD_CAST "module", NULL); -+ -+ cr_xmlNewProp_c(xml_module, BAD_CAST "name", BAD_CAST module->name); -+ cr_xmlNewProp_c(xml_module, BAD_CAST "stream", BAD_CAST module->stream); -+ gchar buf[21]; //20 + '\0' is max number of chars of guint64: G_MAXUINT64 (= 18,446,744,073,709,551,615) -+ snprintf(buf, 21, "%" G_GUINT64_FORMAT, module->version); -+ cr_xmlNewProp_c(xml_module, BAD_CAST "version", BAD_CAST buf); -+ cr_xmlNewProp_c(xml_module, BAD_CAST "context", BAD_CAST module->context); -+ cr_xmlNewProp_c(xml_module, BAD_CAST "arch", BAD_CAST module->arch); -+} -+ -+void - cr_xml_dump_updateinforecord_pkglist(xmlNodePtr update, GSList *collections) - { - xmlNodePtr pkglist; -@@ -83,6 +101,8 @@ cr_xml_dump_updateinforecord_pkglist(xmlNodePtr update, GSList *collections) - BAD_CAST "name", - BAD_CAST col->name); - -+ cr_xml_dump_updatecollectionmodule(collection, col->module); -+ - cr_xml_dump_updatecollectionpackages(collection, col->packages); - } - } -diff --git a/src/xml_parser_internal.h b/src/xml_parser_internal.h -index 6b400eb..e079ece 100644 ---- a/src/xml_parser_internal.h -+++ b/src/xml_parser_internal.h -@@ -151,6 +151,8 @@ typedef struct _cr_ParserData { - Update record object */ - cr_UpdateCollection *updatecollection; /*!< - Update collection object */ -+ cr_UpdateCollectionModule *updatecollectionmodule; /*!< -+ Update collection module object */ - cr_UpdateCollectionPackage *updatecollectionpackage; /*!< - Update collection package object */ - -diff --git a/src/xml_parser_updateinfo.c b/src/xml_parser_updateinfo.c -index 18e5277..c6c6503 100644 ---- a/src/xml_parser_updateinfo.c -+++ b/src/xml_parser_updateinfo.c -@@ -54,6 +54,7 @@ typedef enum { - STATE_PKGLIST, // ---------------------------- - STATE_COLLECTION, - STATE_NAME, -+ STATE_MODULE, - STATE_PACKAGE, - STATE_FILENAME, - STATE_SUM, -@@ -89,6 +90,7 @@ static cr_StatesSwitch stateswitches[] = { - { STATE_PKGLIST, "collection", STATE_COLLECTION, 0 }, - { STATE_COLLECTION, "package", STATE_PACKAGE, 0 }, - { STATE_COLLECTION, "name", STATE_NAME, 1 }, -+ { STATE_COLLECTION, "module", STATE_MODULE, 0 }, - { STATE_PACKAGE, "filename", STATE_FILENAME, 1 }, - { STATE_PACKAGE, "sum", STATE_SUM, 1 }, - { STATE_PACKAGE, "reboot_suggested", STATE_REBOOTSUGGESTED, 0 }, -@@ -141,6 +143,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - // Shortcuts - cr_UpdateRecord *rec = pd->updaterecord; - cr_UpdateCollection *collection = pd->updatecollection; -+ cr_UpdateCollectionModule *module = pd->updatecollectionmodule; - cr_UpdateCollectionPackage *package = pd->updatecollectionpackage; - - switch(pd->state) { -@@ -173,6 +176,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(!pd->updaterecord); - assert(!pd->updatecollection); -+ assert(!pd->updatecollectionmodule); - assert(!pd->updatecollectionpackage); - - rec = cr_updaterecord_new(); -@@ -201,6 +205,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(!pd->updatecollection); -+ assert(!pd->updatecollectionmodule); - assert(!pd->updatecollectionpackage); - val = cr_find_attr("date", attr); - if (val) -@@ -211,6 +216,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(!pd->updatecollection); -+ assert(!pd->updatecollectionmodule); - assert(!pd->updatecollectionpackage); - val = cr_find_attr("date", attr); - if (val) -@@ -223,6 +229,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(!pd->updatecollection); -+ assert(!pd->updatecollectionmodule); - assert(!pd->updatecollectionpackage); - - ref = cr_updatereference_new(); -@@ -251,6 +258,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(!pd->updatecollection); -+ assert(!pd->updatecollectionmodule); - assert(!pd->updatecollectionpackage); - - collection = cr_updatecollection_new(); -@@ -263,6 +271,49 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - - break; - -+ case STATE_MODULE: -+ assert(pd->updateinfo); -+ assert(pd->updaterecord); -+ assert(pd->updatecollection); -+ assert(!pd->updatecollectionmodule); -+ assert(!pd->updatecollectionpackage); -+ -+ module = cr_updatecollectionmodule_new(); -+ if (module) -+ collection->module = module; -+ -+ val = cr_find_attr("name", attr); -+ if (val) -+ module->name = g_string_chunk_insert(module->chunk, val); -+ -+ val = cr_find_attr("stream", attr); -+ if (val) -+ module->stream = g_string_chunk_insert(module->chunk, val); -+ -+ val = cr_find_attr("version", attr); -+ if (val){ -+ gchar *endptr; -+ errno = 0; -+ module->version = strtoull(val, &endptr, 10); -+ if ((errno == ERANGE && (module->version == ULLONG_MAX)) -+ || (errno != 0 && module->version == 0)) { -+ perror("strtoull error when parsing module version"); -+ module->version = 0; -+ } -+ if (endptr == val) -+ module->version = 0; -+ } -+ -+ val = cr_find_attr("context", attr); -+ if (val) -+ module->context = g_string_chunk_insert(module->chunk, val); -+ -+ val = cr_find_attr("arch", attr); -+ if (val) -+ module->arch = g_string_chunk_insert(module->chunk, val); -+ -+ break; -+ - case STATE_PACKAGE: - assert(pd->updateinfo); - assert(pd->updaterecord); -@@ -303,6 +354,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(pd->updatecollection); -+ assert(pd->updatecollectionmodule); - assert(pd->updatecollectionpackage); - val = cr_find_attr("type", attr); - if (val) -@@ -313,6 +365,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) - assert(pd->updateinfo); - assert(pd->updaterecord); - assert(pd->updatecollection); -+ assert(pd->updatecollectionmodule); - assert(pd->updatecollectionpackage); - package->reboot_suggested = TRUE; - break; -@@ -352,6 +405,7 @@ cr_end_handler(void *pdata, G_GNUC_UNUSED const char *element) - case STATE_UPDATED: - case STATE_REFERENCES: - case STATE_REFERENCE: -+ case STATE_MODULE: - case STATE_PKGLIST: - case STATE_REBOOTSUGGESTED: - // All elements with no text data and without need of any -diff --git a/tests/fixtures.h b/tests/fixtures.h -index ee374f5..8567714 100644 ---- a/tests/fixtures.h -+++ b/tests/fixtures.h -@@ -83,5 +83,6 @@ - #define TEST_UPDATEINFO_00 TEST_UPDATEINFO_FILES_PATH"updateinfo_00.xml" - #define TEST_UPDATEINFO_01 TEST_UPDATEINFO_FILES_PATH"updateinfo_01.xml" - #define TEST_UPDATEINFO_02 TEST_UPDATEINFO_FILES_PATH"updateinfo_02.xml.xz" -+#define TEST_UPDATEINFO_03 TEST_UPDATEINFO_FILES_PATH"updateinfo_03.xml" - - #endif -diff --git a/tests/python/tests/test_updatecollection.py b/tests/python/tests/test_updatecollection.py -index f3433c0..71ac7dd 100644 ---- a/tests/python/tests/test_updatecollection.py -+++ b/tests/python/tests/test_updatecollection.py -@@ -16,6 +16,13 @@ class TestCaseUpdateCollection(unittest.TestCase): - self.assertEqual(col.name, None) - self.assertEqual(col.packages, []) - -+ module = cr.UpdateCollectionModule() -+ module.name = "kangaroo" -+ module.stream = "0" -+ module.version = 20180730223407 -+ module.context = "deadbeef" -+ module.arch = "noarch" -+ - pkg = cr.UpdateCollectionPackage() - pkg.name = "foo" - pkg.version = "1.2" -@@ -30,12 +37,21 @@ class TestCaseUpdateCollection(unittest.TestCase): - - col.shortname = "short name" - col.name = "long name" -+ col.module = module - col.append(pkg) - - self.assertEqual(col.shortname, "short name") - self.assertEqual(col.name, "long name") - self.assertEqual(len(col.packages), 1) - -+ # Check if the appended module was appended properly -+ module = col.module -+ self.assertEqual(module.name, "kangaroo") -+ self.assertEqual(module.stream, "0") -+ self.assertEqual(module.version, 20180730223407) -+ self.assertEqual(module.context, "deadbeef") -+ self.assertEqual(module.arch, "noarch") -+ - # Also check if the appended package was appended properly - pkg = col.packages[0] - self.assertEqual(pkg.name, "foo") -diff --git a/tests/python/tests/test_updatecollectionmodule.py b/tests/python/tests/test_updatecollectionmodule.py -new file mode 100644 -index 0000000..1e92b12 ---- /dev/null -+++ b/tests/python/tests/test_updatecollectionmodule.py -@@ -0,0 +1,31 @@ -+import unittest -+import shutil -+import tempfile -+import os.path -+import createrepo_c as cr -+ -+from .fixtures import * -+ -+class TestCaseUpdateCollectionModule(unittest.TestCase): -+ -+ def test_updatecollectionmodule_setters(self): -+ module = cr.UpdateCollectionModule() -+ self.assertTrue(module) -+ -+ self.assertEqual(module.name, None) -+ self.assertEqual(module.stream, None) -+ self.assertEqual(module.version, 0) -+ self.assertEqual(module.context, None) -+ self.assertEqual(module.arch, None) -+ -+ module.name = "foo" -+ module.stream = "0" -+ module.version = 20180730223407 -+ module.context = "deadbeef" -+ module.arch = "noarch" -+ -+ self.assertEqual(module.name, "foo") -+ self.assertEqual(module.stream, "0") -+ self.assertEqual(module.version, 20180730223407) -+ self.assertEqual(module.context, "deadbeef") -+ self.assertEqual(module.arch, "noarch") -diff --git a/tests/python/tests/test_updateinfo.py b/tests/python/tests/test_updateinfo.py -index f3b88e1..727b707 100644 ---- a/tests/python/tests/test_updateinfo.py -+++ b/tests/python/tests/test_updateinfo.py -@@ -123,6 +123,100 @@ class TestCaseUpdateInfo(unittest.TestCase): - now = datetime(now.year, now.month, now.day, now.hour, now.minute, - now.second, 0) - -+ mod = cr.UpdateCollectionModule() -+ mod.name = "kangaroo" -+ mod.stream = "0" -+ mod.version = 18446744073709551615 -+ mod.context = "deadbeef" -+ mod.arch = "x86" -+ -+ pkg = cr.UpdateCollectionPackage() -+ pkg.name = "foo" -+ pkg.version = "1.2" -+ pkg.release = "3" -+ pkg.epoch = "0" -+ pkg.arch = "x86" -+ pkg.src = "foo.src.rpm" -+ pkg.filename = "foo.rpm" -+ pkg.sum = "abcdef" -+ pkg.sum_type = cr.SHA1 -+ pkg.reboot_suggested = True -+ -+ col = cr.UpdateCollection() -+ col.shortname = "short name" -+ col.name = "long name" -+ col.module = mod -+ col.append(pkg) -+ -+ ref = cr.UpdateReference() -+ ref.href = "href" -+ ref.id = "id" -+ ref.type = "type" -+ ref.title = "title" -+ -+ rec = cr.UpdateRecord() -+ rec.fromstr = "from" -+ rec.status = "status" -+ rec.type = "type" -+ rec.version = "version" -+ rec.id = "id" -+ rec.title = "title" -+ rec.issued_date = now -+ rec.updated_date = now -+ rec.rights = "rights" -+ rec.release = "release" -+ rec.pushcount = "pushcount" -+ rec.severity = "severity" -+ rec.summary = "summary" -+ rec.description = "description" -+ rec.solution = "solution" -+ rec.append_collection(col) -+ rec.append_reference(ref) -+ -+ ui = cr.UpdateInfo() -+ ui.append(rec) -+ -+ xml = ui.xml_dump() -+ -+ self.assertEqual(xml, -+""" -+ -+ -+ id -+ title -+ -+ -+ rights -+ release -+ pushcount -+ severity -+ summary -+ description -+ solution -+ -+ -+ -+ -+ -+ long name -+ -+ -+ foo.rpm -+ abcdef -+ -+ -+ -+ -+ -+ -+""" % {"now": now.strftime("%Y-%m-%d %H:%M:%S")}) -+ -+ def test_updateinfo_xml_dump_04(self): -+ now = datetime.now() -+ # Microseconds are always 0 in updateinfo -+ now = datetime(now.year, now.month, now.day, now.hour, now.minute, -+ now.second, 0) -+ - pkg = cr.UpdateCollectionPackage() - pkg.name = "foo" - pkg.version = "1.2" -@@ -135,6 +229,7 @@ class TestCaseUpdateInfo(unittest.TestCase): - pkg.sum_type = cr.SHA1 - pkg.reboot_suggested = True - -+ # Collection without module - col = cr.UpdateCollection() - col.shortname = "short name" - col.name = "long name" -@@ -167,6 +262,99 @@ class TestCaseUpdateInfo(unittest.TestCase): - - ui = cr.UpdateInfo() - ui.append(rec) -+ -+ xml = ui.xml_dump() -+ -+ self.assertEqual(xml, -+""" -+ -+ -+ id -+ title -+ -+ -+ rights -+ release -+ pushcount -+ severity -+ summary -+ description -+ solution -+ -+ -+ -+ -+ -+ long name -+ -+ foo.rpm -+ abcdef -+ -+ -+ -+ -+ -+ -+""" % {"now": now.strftime("%Y-%m-%d %H:%M:%S")}) -+ -+ def test_updateinfo_xml_dump_05(self): -+ now = datetime.now() -+ # Microseconds are always 0 in updateinfo -+ now = datetime(now.year, now.month, now.day, now.hour, now.minute, -+ now.second, 0) -+ -+ # Collection module with unset fields -+ mod = cr.UpdateCollectionModule() -+ mod.version = 18446744073709551615 -+ mod.context = "deadbeef" -+ mod.arch = "x86" -+ -+ pkg = cr.UpdateCollectionPackage() -+ pkg.name = "foo" -+ pkg.version = "1.2" -+ pkg.release = "3" -+ pkg.epoch = "0" -+ pkg.arch = "x86" -+ pkg.src = "foo.src.rpm" -+ pkg.filename = "foo.rpm" -+ pkg.sum = "abcdef" -+ pkg.sum_type = cr.SHA1 -+ pkg.reboot_suggested = True -+ -+ col = cr.UpdateCollection() -+ col.shortname = "short name" -+ col.name = "long name" -+ col.module = mod -+ col.append(pkg) -+ -+ ref = cr.UpdateReference() -+ ref.href = "href" -+ ref.id = "id" -+ ref.type = "type" -+ ref.title = "title" -+ -+ rec = cr.UpdateRecord() -+ rec.fromstr = "from" -+ rec.status = "status" -+ rec.type = "type" -+ rec.version = "version" -+ rec.id = "id" -+ rec.title = "title" -+ rec.issued_date = now -+ rec.updated_date = now -+ rec.rights = "rights" -+ rec.release = "release" -+ rec.pushcount = "pushcount" -+ rec.severity = "severity" -+ rec.summary = "summary" -+ rec.description = "description" -+ rec.solution = "solution" -+ rec.append_collection(col) -+ rec.append_reference(ref) -+ -+ ui = cr.UpdateInfo() -+ ui.append(rec) -+ - xml = ui.xml_dump() - - self.assertEqual(xml, -@@ -190,6 +378,7 @@ class TestCaseUpdateInfo(unittest.TestCase): - - - long name -+ - - foo.rpm - abcdef -diff --git a/tests/test_xml_parser_updateinfo.c b/tests/test_xml_parser_updateinfo.c -index 94768ce..3f0cfee 100644 ---- a/tests/test_xml_parser_updateinfo.c -+++ b/tests/test_xml_parser_updateinfo.c -@@ -168,6 +168,90 @@ test_cr_xml_parse_updateinfo_02(void) - cr_updateinfo_free(ui); - } - -+//Test for module support -+static void -+test_cr_xml_parse_updateinfo_03(void) -+{ -+ GError *tmp_err = NULL; -+ cr_UpdateInfo *ui = cr_updateinfo_new(); -+ cr_UpdateRecord *update; -+ cr_UpdateReference *ref; -+ cr_UpdateCollection *col; -+ cr_UpdateCollectionModule *module; -+ cr_UpdateCollectionPackage *pkg; -+ -+ int ret = cr_xml_parse_updateinfo(TEST_UPDATEINFO_03, ui, -+ NULL, NULL, &tmp_err); -+ -+ g_assert(tmp_err == NULL); -+ g_assert_cmpint(ret, ==, CRE_OK); -+ -+ g_assert_cmpint(g_slist_length(ui->updates), ==, 6); -+ update = g_slist_nth_data(ui->updates, 3); -+ -+ g_assert_cmpstr(update->from, ==, "errata@redhat.com"); -+ g_assert_cmpstr(update->status, ==, "stable"); -+ g_assert_cmpstr(update->type, ==, "enhancement"); -+ g_assert_cmpstr(update->version, ==, "1"); -+ g_assert_cmpstr(update->id, ==, "RHEA-2012:0058"); -+ g_assert_cmpstr(update->title, ==, "Gorilla_Erratum"); -+ g_assert_cmpstr(update->description, ==, "Gorilla_Erratum"); -+ -+ update = g_slist_nth_data(ui->updates, 4); -+ -+ g_assert_cmpstr(update->id, ==, "RHEA-2012:0059"); -+ g_assert_cmpstr(update->title, ==, "Duck_Kangaroo_Erratum"); -+ g_assert_cmpstr(update->description, ==, "Duck_Kangaro_Erratum description"); -+ g_assert_cmpstr(update->issued_date, ==, "2018-01-27 16:08:09"); -+ g_assert_cmpstr(update->updated_date, ==, "2018-07-20 06:00:01 UTC"); -+ g_assert_cmpstr(update->release, ==, "1"); -+ -+ g_assert_cmpint(g_slist_length(update->references), ==, 0); -+ -+ g_assert_cmpint(g_slist_length(update->collections), ==, 2); -+ col = g_slist_nth_data(update->collections, 0); -+ g_assert_cmpstr(col->shortname, ==, ""); -+ g_assert_cmpstr(col->name, ==, "coll_name1"); -+ -+ module = col->module; -+ g_assert_cmpstr(module->name, ==, "kangaroo"); -+ g_assert_cmpstr(module->stream, ==, "0"); -+ g_assert_cmpuint(module->version, ==, 20180730223407); -+ g_assert_cmpstr(module->context, ==, "deadbeef"); -+ g_assert_cmpstr(module->arch, ==, "noarch"); -+ -+ g_assert_cmpint(g_slist_length(col->packages), ==, 1); -+ pkg = col->packages->data; -+ g_assert_cmpstr(pkg->name, ==, "kangaroo"); -+ g_assert_cmpstr(pkg->version, ==, "0.3"); -+ g_assert_cmpstr(pkg->release, ==, "1"); -+ g_assert(!pkg->epoch); -+ g_assert_cmpstr(pkg->arch, ==, "noarch"); -+ g_assert_cmpstr(pkg->src, ==, "http://www.fedoraproject.org"); -+ g_assert_cmpstr(pkg->filename, ==, "kangaroo-0.3-1.noarch.rpm"); -+ g_assert(!pkg->sum); -+ g_assert(!pkg->sum_type); -+ -+ col = g_slist_nth_data(update->collections, 1); -+ g_assert_cmpstr(col->shortname, ==, ""); -+ g_assert_cmpstr(col->name, ==, "coll_name2"); -+ -+ module = col->module; -+ g_assert_cmpstr(module->name, ==, "duck"); -+ g_assert_cmpstr(module->stream, ==, "0"); -+ g_assert_cmpuint(module->version, ==, 20180730233102); -+ g_assert_cmpstr(module->context, ==, "deadbeef"); -+ g_assert_cmpstr(module->arch, ==, "noarch"); -+ -+ g_assert_cmpint(g_slist_length(col->packages), ==, 1); -+ pkg = col->packages->data; -+ g_assert_cmpstr(pkg->name, ==, "duck"); -+ g_assert_cmpstr(pkg->version, ==, "0.7"); -+ g_assert_cmpstr(pkg->filename, ==, "duck-0.7-1.noarch.rpm"); -+ -+ cr_updateinfo_free(ui); -+} -+ - int - main(int argc, char *argv[]) - { -@@ -179,6 +263,8 @@ main(int argc, char *argv[]) - test_cr_xml_parse_updateinfo_01); - g_test_add_func("/xml_parser_updateinfo/test_cr_xml_parse_updateinfo_02", - test_cr_xml_parse_updateinfo_02); -+ g_test_add_func("/xml_parser_updateinfo/test_cr_xml_parse_updateinfo_03", -+ test_cr_xml_parse_updateinfo_03); - - return g_test_run(); - } -diff --git a/tests/testdata/updateinfo_files/updateinfo_03.xml b/tests/testdata/updateinfo_files/updateinfo_03.xml -new file mode 100644 -index 0000000..ddbd99b ---- /dev/null -+++ b/tests/testdata/updateinfo_files/updateinfo_03.xml -@@ -0,0 +1,128 @@ -+ -+ -+ -+ RHEA-2012:0055 -+ Sea_Erratum -+ 1 -+ -+ -+ Sea_Erratum -+ -+ -+ 1 -+ -+ walrus-5.21-1.noarch.rpm -+ -+ -+ penguin-0.9.1-1.noarch.rpm -+ -+ -+ shark-0.1-1.noarch.rpm -+ -+ -+ -+ -+ -+ -+ RHEA-2012:0056 -+ Bird_Erratum -+ 1 -+ -+ -+ ParthaBird_Erratum -+ -+ -+ 1 -+ -+ crow-0.8-1.noarch.rpm -+ -+ -+ stork-0.12-2.noarch.rpm -+ -+ -+ duck-0.6-1.noarch.rpm -+ -+ -+ -+ -+ -+ -+ RHEA-2012:0057 -+ Bear_ErratumPARTHA -+ 1 -+ -+ -+ Bear_Erratum -+ -+ -+ 1 -+ -+ bear-4.1-1.noarch.rpm -+ -+ -+ -+ -+ -+ -+ RHEA-2012:0058 -+ Gorilla_Erratum -+ 1 -+ -+ -+ Gorilla_Erratum -+ -+ -+ 1 -+ -+ gorilla-0.62-1.noarch.rpm -+ -+ -+ -+ -+ -+ -+ RHEA-2012:0059 -+ Duck_Kangaroo_Erratum -+ 1 -+ -+ -+ Duck_Kangaro_Erratum description -+ -+ -+ coll_name1 -+ -+ -+ kangaroo-0.3-1.noarch.rpm -+ -+ -+ -+ coll_name2 -+ -+ -+ duck-0.7-1.noarch.rpm -+ -+ -+ -+ -+ -+ -+ RHEA-2012:0060 -+ Duck_0.8_Erratum -+ 1 -+ -+ -+ Duck_0.8_Erratum description -+ -+ -+ coll_name -+ -+ -+ duck-0.8-1.noarch.rpm -+ -+ -+ -+ -+ --- -libgit2 0.27.8 - diff --git a/SOURCES/0005-Switch-off-html-timestamps-on-documentation-RhBug1731050.patch b/SOURCES/0005-Switch-off-html-timestamps-on-documentation-RhBug1731050.patch deleted file mode 100644 index c7e5228..0000000 --- a/SOURCES/0005-Switch-off-html-timestamps-on-documentation-RhBug1731050.patch +++ /dev/null @@ -1,32 +0,0 @@ -From df4145ae17972b51a2f4e3ccb10c7ed0a6799209 Mon Sep 17 00:00:00 2001 -From: Marek Blaha -Date: Mon, 29 Jul 2019 12:09:07 +0200 -Subject: [PATCH] Switch off html timestamps on documentation (RhBug:1731050) - -This change avoids file conflicts when installing createrepo_c-devel -package for i686 and x86_64 architectures in parallel. -After switching the timestamps off the documentation html files are -identical for both builds and rpm does not consider them conflicting any -more. - -https://bugzilla.redhat.com/show_bug.cgi?id=1731050 ---- - doc/Doxyfile.in.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/doc/Doxyfile.in.in b/doc/Doxyfile.in.in -index bd6b5a7..35a5e75 100644 ---- a/doc/Doxyfile.in.in -+++ b/doc/Doxyfile.in.in -@@ -952,7 +952,7 @@ HTML_COLORSTYLE_GAMMA = 80 - # page will contain the date and time when the page was generated. Setting - # this to NO can help when comparing the output of multiple runs. - --HTML_TIMESTAMP = YES -+HTML_TIMESTAMP = NO - - # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML - # documentation will contain sections that can be hidden and shown after the --- -libgit2 0.28.2 - diff --git a/SPECS/createrepo_c.spec b/SPECS/createrepo_c.spec index ff08f69..cdc44f4 100644 --- a/SPECS/createrepo_c.spec +++ b/SPECS/createrepo_c.spec @@ -1,3 +1,4 @@ +%global libmodulemd_version 2.3.0 %{!?_licensedir:%global license %%doc} # Bash completion (we need different approach for RHEL-6) @@ -15,24 +16,33 @@ %bcond_without drpm %endif -%if 0%{?rhel} > 7 +%if 0%{?fedora} > 29 || 0%{?rhel} > 7 %bcond_with python2 %else %bcond_without python2 %endif +%if 0%{?rhel} || 0%{?fedora} < 29 +%bcond_with zchunk +%else +%bcond_without zchunk +%endif + +%if 0%{?rhel} || 0%{?fedora} < 29 +%bcond_with libmodulemd +%else +%bcond_without libmodulemd +%endif + Summary: Creates a common metadata repository Name: createrepo_c -Version: 0.11.0 -Release: 3%{?dist} +Version: 0.15.1 +Release: 2%{?dist} License: GPLv2+ URL: https://github.com/rpm-software-management/createrepo_c Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz -Patch0: 0001-Consistently-produce-valid-URLs-by-prepending-protocol-RhBug1632121.patch -Patch1: 0002-modifyrepo_c-Prevent-doubling-of-compression-testgzgz-RhBug1639287.patch -Patch2: 0003-Correct-pkg-count-in-headers-if-there-were-invalid-pkgs-RhBug1596211.patch -Patch3: 0004-Add-support-for-modular-errata-RhBug1656584.patch -Patch4: 0005-Switch-off-html-timestamps-on-documentation-RhBug1731050.patch +Patch1: 0001-Libmagic-to-follow-symlinks-RhBug1776399.patch +Patch2: 0002-Add-reboot_suggested-to-UpdateRecord-RhBug1772466.patch BuildRequires: cmake BuildRequires: gcc @@ -48,6 +58,15 @@ BuildRequires: rpm-devel >= 4.8.0-28 BuildRequires: sqlite-devel BuildRequires: xz-devel BuildRequires: zlib-devel +%if %{with zchunk} +BuildRequires: pkgconfig(zck) >= 0.9.11 +BuildRequires: zchunk +%endif +%if %{with libmodulemd} +BuildRequires: pkgconfig(modulemd-2.0) >= %{libmodulemd_version} +BuildRequires: libmodulemd +Requires: libmodulemd%{?_isa} >= %{libmodulemd_version} +%endif Requires: %{name}-libs = %{version}-%{release} %if 0%{?rhel} == 6 Requires: rpm >= 4.8.0-28 @@ -56,10 +75,13 @@ BuildRequires: bash-completion Requires: rpm >= 4.9.0 %endif %if %{with drpm} -BuildRequires: drpm-devel >= 0.1.3 +BuildRequires: drpm-devel >= 0.4.0 %endif + +%if 0%{?fedora} || 0%{?rhel} > 7 Obsoletes: createrepo < 0.11.0 Provides: createrepo = %{version}-%{release} +%endif %description C implementation of Createrepo. @@ -88,7 +110,11 @@ Summary: Python bindings for the createrepo_c library %{?python_provide:%python_provide python2-%{name}} BuildRequires: python2-devel BuildRequires: python2-nose +%if 0%{?rhel} && 0%{?rhel} <= 7 +BuildRequires: python-sphinx +%else BuildRequires: python2-sphinx +%endif Requires: %{name}-libs = %{version}-%{release} %description -n python2-%{name} @@ -122,7 +148,7 @@ mkdir build-py3 # Build createrepo_c with Python 2 %if %{with python2} pushd build-py2 - %cmake ../ + %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python2} %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_libmodulemd:-DWITH_LIBMODULEMD=OFF} make %{?_smp_mflags} RPM_OPT_FLAGS="%{optflags}" %if %{without python3} # Build C documentation @@ -134,7 +160,7 @@ popd # Build createrepo_c with Pyhon 3 %if %{with python3} pushd build-py3 - %cmake ../ -DPYTHON_DESIRED:str=3 + %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python3} %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_libmodulemd:-DWITH_LIBMODULEMD=OFF} make %{?_smp_mflags} RPM_OPT_FLAGS="%{optflags}" # Build C documentation make doc-c @@ -180,11 +206,18 @@ pushd build-py3 popd %endif +%if 0%{?fedora} || 0%{?rhel} > 7 ln -sr %{buildroot}%{_bindir}/createrepo_c %{buildroot}%{_bindir}/createrepo ln -sr %{buildroot}%{_bindir}/mergerepo_c %{buildroot}%{_bindir}/mergerepo ln -sr %{buildroot}%{_bindir}/modifyrepo_c %{buildroot}%{_bindir}/modifyrepo +%endif +%if 0%{?rhel} && 0%{?rhel} <= 7 +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig +%else %ldconfig_scriptlets libs +%endif %files %doc README.md @@ -196,10 +229,13 @@ ln -sr %{buildroot}%{_bindir}/modifyrepo_c %{buildroot}%{_bindir}/modifyrepo %{_bindir}/createrepo_c %{_bindir}/mergerepo_c %{_bindir}/modifyrepo_c +%{_bindir}/sqliterepo_c + +%if 0%{?fedora} || 0%{?rhel} > 7 %{_bindir}/createrepo %{_bindir}/mergerepo %{_bindir}/modifyrepo -%{_bindir}/sqliterepo_c +%endif %files libs %license COPYING @@ -218,14 +254,48 @@ ln -sr %{buildroot}%{_bindir}/modifyrepo_c %{buildroot}%{_bindir}/modifyrepo %if %{with python2} %files -n python2-%{name} %{python2_sitearch}/%{name}/ +%{python2_sitearch}/%{name}-%{version}-py%{python2_version}.egg-info %endif %if %{with python3} %files -n python3-%{name} %{python3_sitearch}/%{name}/ +%{python3_sitearch}/%{name}-%{version}-py%{python3_version}.egg-info %endif %changelog +* Mon Jan 13 2020 Ales Matej - 0.15.1-2 +- Add reboot_suggested to UpdateRecord (RhBug:1772466) +- Explicitly output boolean values for updateinfo.xml (RhBug:1772466) +- Fix modifyrepo_c with modules.yaml as a symbolic link (RhBug:1776399) + +* Tue Oct 22 2019 Ales Matej - 0.15.1-1 +- Update to 0.15.1 +- Allow pip to see installation of python3-createrepo_c +- Imporove documentation +- Remove dependency on deltarpm in favour of drpm +- Obsolete createrepo on all Fedoras again (RhBug:1702771) +- Fix issue with createrepo_c hanging at the end (RhBug:1714666) +- Don't include packages with forbidden control chars in repodata +- Depend on the appropriate minimum version of libmodulemd +- Add --pkgorigins mode for Koji +- Prevent exiting with 0 if errors occur while finalizing repodata. +- Add support for reading and merging module metadata +- Update --keep-all-metadata to keep all additional metadata, not just updateinfo and groupfile (RhBug:1639287) +- mergerepo_c: Add support for --koji simple mode +- Fix generating corrupted sqlite files (RhBug: 1696808) +- Do not obsolete createrepo on Fedora < 31 +- mergerepo_c: check if nevra is NULL and warn user about src.rpm naming +- Include file timestamp in repomd.xml to allow reproducing exact metadata as produced in the past +- Enhance support of zchunk +- Support of zchunk +- [spec] Fix ldconfig for rhel <= 7 +- Fix "CR_DELTA_RPM_SUPPORT" redefined warnings +- Set to build against Python 3 by default +- Update README +- Add mergerepo_c --repo-prefix-search and --repo-prefix-replace. +- Fix missing packages in mergerepo_c in case multiple VR exists for single pkg in repo. + * Thu Aug 08 2019 Pavla Kratochvilova - 0.11.0-3 - Backport patch to switch off timestamps on documentation in order to remove file conflicts (RhBug:1738788)