From: Michael Tremer Date: Tue, 10 May 2022 11:32:32 +0000 (+0000) Subject: packages: Write package metadata in JSON format X-Git-Tag: 0.9.28~801 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b59c9fa293b770630ed6d4a552d278efb9f1c486;p=pakfire.git packages: Write package metadata in JSON format This is starting a new package format which should be easier to write and parse than our own format. It should also be quite extensible. Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 50fe84f54..915888c91 100644 --- a/Makefile.am +++ b/Makefile.am @@ -201,7 +201,8 @@ libpakfire_parser_la_SOURCES = \ src/libpakfire/parser/scanner.l libpakfire_parser_la_CFLAGS = \ - $(AM_CFLAGS) + $(AM_CFLAGS) \ + $(JSON_C_CFLAGS) libpakfire_parser_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ @@ -382,6 +383,9 @@ tests_libpakfire_main_CPPFLAGS = \ $(TESTSUITE_CPPFLAGS) \ -DTEST_ROOTFS=\"$(TEST_ROOTFS)\" +tests_libpakfire_main_CFLAGS = \ + $(TESTSUITE_CFLAGS) + tests_libpakfire_main_LDADD = \ $(TESTSUITE_LDADD) @@ -491,6 +495,9 @@ dist_tests_libpakfire_packager_SOURCES = \ tests_libpakfire_packager_CPPFLAGS = \ $(TESTSUITE_CPPFLAGS) +tests_libpakfire_packager_CFLAGS = \ + $(TESTSUITE_CFLAGS) + tests_libpakfire_packager_LDADD = \ $(TESTSUITE_LDADD) @@ -688,6 +695,9 @@ tests_libtestsuite_la_SOURCES = \ tests/testsuite.c \ tests/testsuite.h +tests_libtestsuite_la_CFLAGS = \ + $(TESTSUITE_CFLAGS) + tests_libtestsuite_la_CPPFLAGS = \ $(TESTSUITE_CPPFLAGS) @@ -698,6 +708,9 @@ TESTSUITE_CPPFLAGS = \ -DTEST_ROOTFS=\"$(TEST_ROOTFS)\" \ -DPAKFIRE_PRIVATE +TESTSUITE_CFLAGS = \ + $(JSON_C_CFLAGS) + TESTSUITE_LDADD = \ tests/libtestsuite.la \ libpakfire.la \ diff --git a/src/libpakfire/include/pakfire/package.h b/src/libpakfire/include/pakfire/package.h index 6279e921d..30c1a4702 100644 --- a/src/libpakfire/include/pakfire/package.h +++ b/src/libpakfire/include/pakfire/package.h @@ -124,6 +124,8 @@ enum pakfire_package_dump_flags { #include +#include + #include #include @@ -149,6 +151,8 @@ void pakfire_package_add_supplements(struct pakfire_package* pkg, const char* de void pakfire_package_add_enhances(struct pakfire_package* pkg, const char* dep); int pakfire_package_has_rich_deps(struct pakfire_package* pkg); +struct json_object* pakfire_package_to_json(struct pakfire_package* pkg); + #endif #endif /* PAKFIRE_PACKAGE_H */ diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index 9d61e6d51..a4f098e5e 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -105,6 +105,12 @@ int pakfire_archive_copy_data_to_buffer(struct pakfire* pakfire, struct archive* // JSON Stuff struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const char* path); +int pakfire_json_add_string(struct pakfire* pakfire, + struct json_object* json, const char* name, const char* value); +int pakfire_json_add_integer(struct pakfire* pakfire, + struct json_object* json, const char* name, int value); +int pakfire_json_add_string_array(struct pakfire* pakfire, + struct json_object* json, const char* name, char** array); // Time Stuff diff --git a/src/libpakfire/package.c b/src/libpakfire/package.c index cac9d95de..16084f596 100644 --- a/src/libpakfire/package.c +++ b/src/libpakfire/package.c @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -1374,3 +1376,263 @@ int pakfire_package_set_filelist_from_string(struct pakfire_package* pkg, const return 0; } + +static int _pakfire_package_add_json_dependencies( + struct pakfire_package* pkg, + struct json_object* json, + const char* name, + char** (*func)(struct pakfire_package* pkg)) { + // Fetch dependencies + char** dependencies = func(pkg); + + // Nothing to do if there are no dependencies + if (!dependencies) + return 0; + + // Add dependencies + int r = pakfire_json_add_string_array(pkg->pakfire, json, name, dependencies); + if (r) + goto ERROR; + +ERROR: + if (dependencies) { + for (char** dep = dependencies; *dep; dep++) + free(*dep); + free(dependencies); + } + + return r; +} + +static int pakfire_package_add_json_dependencies( + struct pakfire_package* pkg, struct json_object* md) { + int r = 0; + + // Create new dependencies object + struct json_object* object = json_object_new_object(); + if (!object) + return 1; + + // Pre-requires + r = _pakfire_package_add_json_dependencies(pkg, object, + "prerequires", pakfire_package_get_prerequires); + if (r) + goto ERROR; + + // Requires + r = _pakfire_package_add_json_dependencies(pkg, object, + "requires", pakfire_package_get_requires); + if (r) + goto ERROR; + + // Provides + r = _pakfire_package_add_json_dependencies(pkg, object, + "provides", pakfire_package_get_provides); + if (r) + goto ERROR; + + // Conflicts + r = _pakfire_package_add_json_dependencies(pkg, object, + "conflicts", pakfire_package_get_conflicts); + if (r) + goto ERROR; + + // Obsoletes + r = _pakfire_package_add_json_dependencies(pkg, object, + "obsoletes", pakfire_package_get_obsoletes); + if (r) + goto ERROR; + + // Recommends + r = _pakfire_package_add_json_dependencies(pkg, object, + "recommends", pakfire_package_get_recommends); + if (r) + goto ERROR; + + // Suggests + r = _pakfire_package_add_json_dependencies(pkg, object, + "suggests", pakfire_package_get_suggests); + if (r) + goto ERROR; + + // Supplements + r = _pakfire_package_add_json_dependencies(pkg, object, + "supplements", pakfire_package_get_supplements); + if (r) + goto ERROR; + + // Enhances + r = _pakfire_package_add_json_dependencies(pkg, object, + "enhances", pakfire_package_get_enhances); + if (r) + goto ERROR; + + // Add object + r = json_object_object_add(md, "dependencies", object); + if (r) + goto ERROR; + +ERROR: + if (r) + json_object_put(object); + + return r; +} + +static int pakfire_package_add_build_metadata(struct pakfire_package* pkg, + struct json_object* md) { + int r; + + // Create a new JSON object + struct json_object* object = json_object_new_object(); + if (!object) + return 1; + + // Add pakfire version that generated this metadata + r = pakfire_json_add_string(pkg->pakfire, object, "pakfire", PACKAGE_VERSION); + if (r) + goto ERROR; + + // Write build host + const char* build_host = pakfire_package_get_build_host(pkg); + if (build_host) { + r = pakfire_json_add_string(pkg->pakfire, object, "host", build_host); + if (r) + goto ERROR; + } + + // Write build id + const char* build_id = pakfire_package_get_build_id(pkg); + if (build_id) { + r = pakfire_json_add_string(pkg->pakfire, object, "id", build_id); + if (r) + goto ERROR; + } + + // Write build host + time_t build_time = pakfire_package_get_build_time(pkg); + if (build_time) { + r = pakfire_json_add_integer(pkg->pakfire, object, "time", build_time); + if (r) + goto ERROR; + } + + // Add object + r = json_object_object_add(md, "build", object); + if (r) + goto ERROR; + +ERROR: + if (r) + json_object_put(object); + + return r; +} + +struct json_object* pakfire_package_to_json(struct pakfire_package* pkg) { + struct json_object* md = json_object_new_object(); + int r = 0; + + // Name + const char* name = pakfire_package_get_name(pkg); + if (name) { + r = pakfire_json_add_string(pkg->pakfire, md, "name", name); + if (r) + goto ERROR; + } + + // EVR + const char* evr = pakfire_package_get_evr(pkg); + if (evr) { + r = pakfire_json_add_string(pkg->pakfire, md, "evr", evr); + if (r) + goto ERROR; + } + + // Arch + const char* arch = pakfire_package_get_arch(pkg); + if (arch) { + r = pakfire_json_add_string(pkg->pakfire, md, "arch", arch); + if (r) + goto ERROR; + } + + // UUID + const char* uuid = pakfire_package_get_uuid(pkg); + if (uuid) { + r = pakfire_json_add_string(pkg->pakfire, md, "uuid", uuid); + if (r) + goto ERROR; + } + + // Groups + char* groups = pakfire_package_get_groups(pkg); + if (groups) { + r = pakfire_json_add_string(pkg->pakfire, md, "groups", groups); + free(groups); + if (r) + goto ERROR; + } + + // Maintainer + const char* maintainer = pakfire_package_get_maintainer(pkg); + if (maintainer) { + r = pakfire_json_add_string(pkg->pakfire, md, "maintainer", maintainer); + if (r) + goto ERROR; + } + + // URL + const char* url = pakfire_package_get_url(pkg); + if (url) { + r = pakfire_json_add_string(pkg->pakfire, md, "url", url); + if (r) + goto ERROR; + } + + // License + const char* license = pakfire_package_get_license(pkg); + if (license) { + r = pakfire_json_add_string(pkg->pakfire, md, "license", license); + if (r) + goto ERROR; + } + + // Summary + const char* summary = pakfire_package_get_summary(pkg); + if (summary) { + r = pakfire_json_add_string(pkg->pakfire, md, "summary", summary); + if (r) + goto ERROR; + } + + // Description + const char* description = pakfire_package_get_description(pkg); + if (description) { + r = pakfire_json_add_string(pkg->pakfire, md, "description", description); + if (r) + goto ERROR; + } + + // Installed package size + size_t installsize = pakfire_package_get_installsize(pkg); + r = pakfire_json_add_integer(pkg->pakfire, md, "size", installsize); + if (r) + goto ERROR; + + // Generate dependency metadata + r = pakfire_package_add_json_dependencies(pkg, md); + if (r) + goto ERROR; + + // Generate build metadata + r = pakfire_package_add_build_metadata(pkg, md); + if (r) + goto ERROR; + +ERROR: + if (r) + json_object_put(md); + + return md; +} diff --git a/src/libpakfire/packager.c b/src/libpakfire/packager.c index 4dbda9ecf..d3791bab4 100644 --- a/src/libpakfire/packager.c +++ b/src/libpakfire/packager.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -458,211 +460,41 @@ static int pakfire_packager_write_format(struct pakfire_packager* packager, return 0; } -static char* pakfire_package_make_metadata(struct pakfire_packager* packager) { - struct pakfire_package* pkg = packager->pkg; - - char* buffer = NULL; - int r; +static char* pakfire_packager_make_metadata(struct pakfire_packager* packager) { + char* result = NULL; - // Print version information - r = asprintf(&buffer, "# Pakfire %s\n\n", PACKAGE_VERSION); - if (r < 0) + // Convert all package metadata to JSON + struct json_object* md = pakfire_package_to_json(packager->pkg); + if (!md) goto ERROR; - // Write package information - r = asprintf(&buffer, "%s# Package information\npackage\n", buffer); - if (r < 0) + // Serialize JSON to file + const char* s = json_object_to_json_string_ext(md, + JSON_C_TO_STRING_PRETTY|JSON_C_TO_STRING_PRETTY_TAB); + if (!s) goto ERROR; - // Write package name - r = asprintf(&buffer, "%s\tname = %s\n", buffer, pakfire_package_get_name(pkg)); - if (r < 0) + // Copy result onto heap + result = strdup(s); + if (!result) goto ERROR; - // Write package EVR - r = asprintf(&buffer, "%s\tevr = %s\n", buffer, pakfire_package_get_evr(pkg)); - if (r < 0) - goto ERROR; - - // Write package arch - r = asprintf(&buffer, "%s\tarch = %s\n", buffer, pakfire_package_get_arch(pkg)); - if (r < 0) - goto ERROR; - - // Write package UUID - r = asprintf(&buffer, "%s\tuuid = %s\n", buffer, pakfire_package_get_uuid(pkg)); - if (r < 0) - goto ERROR; - - // Write package groups - const char* groups = pakfire_package_get_groups(pkg); - if (groups) { - r = asprintf(&buffer, "%s\tgroups = %s\n", buffer, groups); - if (r < 0) - goto ERROR; - } - - // Write package maintainer - const char* maintainer = pakfire_package_get_maintainer(pkg); - if (maintainer) { - r = asprintf(&buffer, "%s\tmaintainer = %s\n", buffer, maintainer); - if (r < 0) - goto ERROR; - } - - // Write package url - const char* url = pakfire_package_get_url(pkg); - if (url) { - r = asprintf(&buffer, "%s\turl = %s\n", buffer, url); - if (r < 0) - goto ERROR; - } - - // Write package license - const char* license = pakfire_package_get_license(pkg); - if (license) { - r = asprintf(&buffer, "%s\tlicense = %s\n", buffer, license); - if (r < 0) - goto ERROR; - } - - // Write package summary - const char* summary = pakfire_package_get_summary(pkg); - if (summary) { - r = asprintf(&buffer, "%s\tsummary = %s\n", buffer, summary); - if (r < 0) - goto ERROR; - } - - // XXX description - - size_t size = pakfire_package_get_installsize(pkg); - r = asprintf(&buffer, "%s\tsize = %zu\n", buffer, size); - if (r < 0) - goto ERROR; - - // End package block - r = asprintf(&buffer, "%send\n\n", buffer); - if (r < 0) - goto ERROR; - - // Write build information - r = asprintf(&buffer, "%s# Build information\nbuild\n", buffer); - if (r < 0) - goto ERROR; - - // Write build host - const char* build_host = pakfire_package_get_build_host(pkg); - if (build_host) { - r = asprintf(&buffer, "%s\thost = %s\n", buffer, build_host); - if (r < 0) - goto ERROR; - } - - // Write build id - const char* build_id = pakfire_package_get_build_id(pkg); - if (build_id) { - r = asprintf(&buffer, "%s\tid = %s\n", buffer, build_id); - if (r < 0) - goto ERROR; - } - - // Write build host - time_t build_time = pakfire_package_get_build_time(pkg); - if (build_host) { - r = asprintf(&buffer, "%s\ttime = %lu\n", buffer, build_time); - if (r < 0) - goto ERROR; - } - - // End build block - r = asprintf(&buffer, "%send\n\n", buffer); - if (r < 0) - goto ERROR; - -#if 0 - // Write distribution information - r = asprintf(&buffer, "%s# Distribution information\ndistribution\n", buffer); - if (r < 0) - goto ERROR; - - // End distribution block - r = asprintf(&buffer, "%send\n\n", buffer); - if (r < 0) - goto ERROR; -#endif - - // Write dependency information - r = asprintf(&buffer, "%s# Dependency information\ndependencies\n", buffer); - if (r < 0) - goto ERROR; - - const struct dependencies { - const char* type; - char** (*func)(struct pakfire_package* pkg); - } dependencies[] = { - { "prerequires", pakfire_package_get_prerequires }, - { "requires", pakfire_package_get_requires }, - { "provides", pakfire_package_get_provides }, - { "conflicts", pakfire_package_get_conflicts }, - { "obsoletes", pakfire_package_get_obsoletes }, - { "recommends", pakfire_package_get_recommends }, - { "suggests", pakfire_package_get_suggests }, - { "supplements", pakfire_package_get_supplements }, - { "enhances", pakfire_package_get_enhances }, - { NULL }, - }; - - for (const struct dependencies* d = dependencies; d->type; d++) { - char** list = d->func(pkg); - if (!list) - continue; - - // Write header - r = asprintf(&buffer, "%s\t%s\n", buffer, d->type); - if (r < 0) { - goto ERROR; - } - - for (char** dep = list; *dep; dep++) { - asprintf(&buffer, "%s\t\t%s\n", buffer, *dep); - free(*dep); - } - free(list); - - // End block - r = asprintf(&buffer, "%s\tend\n", buffer); - if (r < 0) - goto ERROR; - } - - // End dependencies block - r = asprintf(&buffer, "%send\n\n", buffer); - if (r < 0) - goto ERROR; - - // EOF - r = asprintf(&buffer, "%s# EOF\n", buffer); - if (r < 0) - goto ERROR; - - return buffer; - ERROR: - if (buffer) - free(buffer); + // Free metadata + if (md) + json_object_put(md); - return NULL; + return result; } static int pakfire_packager_write_metadata(struct pakfire_packager* packager, struct archive* a, struct archive* mtree) { // Make metadata - char* buffer = pakfire_package_make_metadata(packager); + char* buffer = pakfire_packager_make_metadata(packager); if (!buffer) return 1; - DEBUG(packager->pakfire, "Generated package metadata:\n%s", buffer); + DEBUG(packager->pakfire, "Generated package metadata:\n%s\n", buffer); // Write buffer int r = pakfire_packager_write_file_from_buffer(packager, a, mtree, diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index b46329952..99a9b61b5 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -1112,6 +1112,61 @@ struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const return json; } +int pakfire_json_add_string(struct pakfire* pakfire, struct json_object* json, + const char* name, const char* value) { + // No string? Nothing to do + if (!value) + return 0; + + // Convert string to JSON object + struct json_object* object = json_object_new_string(value); + if (!object) + return 1; + + // Add the object + return json_object_object_add(json, name, object); +} + +int pakfire_json_add_string_array(struct pakfire* pakfire, struct json_object* json, + const char* name, char** array) { + int r = 1; + + // Allocate a new array + struct json_object* object = json_object_new_array(); + if (!object) + goto ERROR; + + // Add all items on list to the array + for (char** item = array; *item; item++) { + r = json_object_array_add(object, json_object_new_string(*item)); + if (r) + goto ERROR; + } + + // Add object + r = json_object_object_add(json, name, object); + if (r) + goto ERROR; + +ERROR: + // Free JSON object on error + if (r) + json_object_put(object); + + return r; +} + +int pakfire_json_add_integer(struct pakfire* pakfire, struct json_object* json, + const char* name, int value) { + // Convert integer to JSON object + struct json_object* object = json_object_new_int64(value); + if (!object) + return 1; + + // Add the object + return json_object_object_add(json, name, object); +} + // Time Stuff static void timespec_normalize(struct timespec* t) {