]> git.ipfire.org Git - pakfire.git/commitdiff
packages: Write package metadata in JSON format
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 10 May 2022 11:32:32 +0000 (11:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 10 May 2022 11:32:32 +0000 (11:32 +0000)
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 <michael.tremer@ipfire.org>
Makefile.am
src/libpakfire/include/pakfire/package.h
src/libpakfire/include/pakfire/util.h
src/libpakfire/package.c
src/libpakfire/packager.c
src/libpakfire/util.c

index 50fe84f547b25311229d4697ca8f35460e42b7c2..915888c9114ac47e624ecd54e4c77032001bae0a 100644 (file)
@@ -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 \
index 6279e921dee2cf9a1fc61d7f29a02ad95426fe5d..30c1a4702b15969521ac6a6cfa859562007b3323 100644 (file)
@@ -124,6 +124,8 @@ enum pakfire_package_dump_flags {
 
 #include <stdint.h>
 
+#include <json.h>
+
 #include <solv/pooltypes.h>
 #include <uuid/uuid.h>
 
@@ -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 */
index 9d61e6d511fa1c5775ba875dec94fd445b1c88ec..a4f098e5e91bf816a17c66508225905ac7e5c7fd 100644 (file)
@@ -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
 
index cac9d95de516c3cf1707af102f69c8d2d9d9f2de..16084f596b422ad9c0da84666a68ef445fe73207 100644 (file)
@@ -25,6 +25,8 @@
 #include <time.h>
 #include <uuid/uuid.h>
 
+#include <json.h>
+
 #include <solv/evr.h>
 #include <solv/pool.h>
 #include <solv/repo.h>
@@ -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;
+}
index 4dbda9ecf8fd750b6b84c37446812d67600a6895..d3791bab4f605f5cb7635e05de24ac97a19fdf53 100644 (file)
@@ -30,6 +30,8 @@
 #include <archive.h>
 #include <archive_entry.h>
 
+#include <json.h>
+
 #include <pakfire/archive.h>
 #include <pakfire/constants.h>
 #include <pakfire/logging.h>
@@ -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,
index b4632995259e5de69c2d1a057f45f507e56e7773..99a9b61b57eebd151f1f8c3d3639335f59dcb7ef 100644 (file)
@@ -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) {