From: Michael Tremer Date: Mon, 25 Sep 2023 19:02:56 +0000 (+0000) Subject: config: Refactor data model and iterating over sections X-Git-Tag: 0.9.30~1638 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a01c065c372a27e7e03781c86307d7700516f0b1;p=pakfire.git config: Refactor data model and iterating over sections Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/config.c b/src/libpakfire/config.c index 5dd8c266c..b5650e790 100644 --- a/src/libpakfire/config.c +++ b/src/libpakfire/config.c @@ -33,11 +33,18 @@ #define SECTION_MAX_LENGTH 256 #define LINE_MAX_LENGTH 1024 -struct pakfire_config_entry { - STAILQ_ENTRY(pakfire_config_entry) nodes; +struct pakfire_config_section { + STAILQ_ENTRY(pakfire_config_section) nodes; // Section name - char section[SECTION_MAX_LENGTH]; + char name[SECTION_MAX_LENGTH]; + + // Entries + STAILQ_HEAD(entries, pakfire_config_entry) entries; +}; + +struct pakfire_config_entry { + STAILQ_ENTRY(pakfire_config_entry) nodes; // Key & Value char key[KEY_MAX_LENGTH]; @@ -47,7 +54,7 @@ struct pakfire_config_entry { struct pakfire_config { int nrefs; - STAILQ_HEAD(entries, pakfire_config_entry) entries; + STAILQ_HEAD(sections, pakfire_config_section) sections; }; int pakfire_config_create(struct pakfire_config** config) { @@ -59,22 +66,39 @@ int pakfire_config_create(struct pakfire_config** config) { c->nrefs = 1; // Initialise entries - STAILQ_INIT(&c->entries); + STAILQ_INIT(&c->sections); *config = c; return 0; } -static void pakfire_config_entry_free(struct pakfire_config_entry* entry) { +static void pakfire_config_free_entry(struct pakfire_config_entry* entry) { free(entry); } +static void pakfire_config_free_section(struct pakfire_config_section* section) { + struct pakfire_config_entry* entry = NULL; + + // Free all entries + while (!STAILQ_EMPTY(§ion->entries)) { + entry = STAILQ_FIRST(§ion->entries); + STAILQ_REMOVE_HEAD(§ion->entries, nodes); + + pakfire_config_free_entry(entry); + } + + free(section); +} + static void pakfire_config_free(struct pakfire_config* config) { - while (!STAILQ_EMPTY(&config->entries)) { - struct pakfire_config_entry* entry = STAILQ_FIRST(&config->entries); - STAILQ_REMOVE_HEAD(&config->entries, nodes); + struct pakfire_config_section* section = NULL; + + // Free all sections + while (!STAILQ_EMPTY(&config->sections)) { + section = STAILQ_FIRST(&config->sections); + STAILQ_REMOVE_HEAD(&config->sections, nodes); - pakfire_config_entry_free(entry); + pakfire_config_free_section(section); } free(config); @@ -94,6 +118,50 @@ struct pakfire_config* pakfire_config_unref(struct pakfire_config* config) { return NULL; } +static struct pakfire_config_section* pakfire_config_create_section( + struct pakfire_config* config, const char* name) { + struct pakfire_config_section* section = NULL; + int r; + + // Allocate a new section + section = calloc(1, sizeof(*section)); + if (!section) + goto ERROR; + + // Initialize entries + STAILQ_INIT(§ion->entries); + + // Store name + r = pakfire_string_set(section->name, name); + if (r) + goto ERROR; + + // Append it to the list of sections + STAILQ_INSERT_TAIL(&config->sections, section, nodes); + + // Return the section + return section; + +ERROR: + if (section) + pakfire_config_free_section(section); + + return NULL; +} + +static struct pakfire_config_section* pakfire_config_get_section( + struct pakfire_config* config, const char* name) { + struct pakfire_config_section* section = NULL; + + // Find an existing section + STAILQ_FOREACH(section, &config->sections, nodes) { + if (strcmp(section->name, name) == 0) + return section; + } + + return NULL; +} + static int pakfire_config_entry_is_multiline(const struct pakfire_config_entry* entry) { const char* p = strchr(entry->value, '\n'); @@ -104,16 +172,14 @@ static int pakfire_config_entry_is_multiline(const struct pakfire_config_entry* } static struct pakfire_config_entry* pakfire_config_create_entry( - struct pakfire_config* config, const char* section, const char* key) { - struct pakfire_config_entry* entry = calloc(1, sizeof(*entry)); - if (!entry) - return NULL; - + struct pakfire_config* config, const char* name, const char* key) { + struct pakfire_config_section* section = NULL; + struct pakfire_config_entry* entry = NULL; int r; - // Store section - r = pakfire_string_set(entry->section, section); - if (r) + // Allocate a new entry + entry = calloc(1, sizeof(*entry)); + if (!entry) goto ERROR; // Store key @@ -121,18 +187,29 @@ static struct pakfire_config_entry* pakfire_config_create_entry( if (r) goto ERROR; + // Fetch the section + section = pakfire_config_get_section(config, name); + if (!section) { + section = pakfire_config_create_section(config, name); + if (!section) + goto ERROR; + } + // Append it to the list of entries - STAILQ_INSERT_TAIL(&config->entries, entry, nodes); + STAILQ_INSERT_TAIL(§ion->entries, entry, nodes); return entry; ERROR: - pakfire_config_entry_free(entry); + if (entry) + pakfire_config_free_entry(entry); + return NULL; } static struct pakfire_config_entry* pakfire_config_find(struct pakfire_config* config, - const char* section, const char* key) { + const char* name, const char* key) { + struct pakfire_config_section* section = NULL; struct pakfire_config_entry* entry = NULL; // Check for valid input @@ -142,20 +219,17 @@ static struct pakfire_config_entry* pakfire_config_find(struct pakfire_config* c } // Treat NULL as an empty section - if (!section) - section = ""; + if (!name) + name = ""; - STAILQ_FOREACH(entry, &config->entries, nodes) { - // Section must match - if (strcmp(entry->section, section) != 0) - continue; - - // Key must match - if (strcmp(entry->key, key) != 0) - continue; + // Fetch the section + section = pakfire_config_get_section(config, name); + if (!section) + return NULL; - // Match! - return entry; + STAILQ_FOREACH(entry, §ion->entries, nodes) { + if (strcmp(entry->key, key) == 0) + return entry; } // No match @@ -305,54 +379,44 @@ FILE* pakfire_config_get_fopen(struct pakfire_config* config, return NULL; } -static int pakfire_section_in_sections(const char** sections, const char* section) { - if (!sections) - return 0; - - for (const char** s = sections; *s; s++) { - if (strcmp(section, *s) == 0) - return 1; - } - - return 0; -} - -const char** pakfire_config_sections(struct pakfire_config* config) { - struct pakfire_config_entry* entry = NULL; +int pakfire_config_walk_sections(struct pakfire_config* config, + pakfire_config_walk_callback callback, void* p) { + struct pakfire_config_section* default_section = NULL; + struct pakfire_config_section* section = NULL; + int r = 0; - const char** sections = NULL; - size_t num_sections = 0; + // Try to fetch the default section + default_section = pakfire_config_get_section(config, ""); - STAILQ_FOREACH(entry, &config->entries, nodes) { - // Skip empty sections - if (!*entry->section) - continue; + // Run the default section first + if (default_section) { + r = callback(config, default_section->name, p); + if (r) + goto ERROR; + } - // Skip if this section is already on the list - if (pakfire_section_in_sections(sections, entry->section)) + // Then iterate over all other sections + STAILQ_FOREACH(section, &config->sections, nodes) { + // Skip the default section + if (section == default_section) continue; - // Make space in the array - sections = reallocarray(sections, sizeof(*sections), ++num_sections + 1); - if (!sections) - return NULL; - - sections[num_sections - 1] = entry->section; - - // Terminate the array - sections[num_sections] = NULL; + r = callback(config, section->name, p); + if (r) + goto ERROR; } - return sections; +ERROR: + return r; } -int pakfire_config_has_section(struct pakfire_config* config, const char* section) { - struct pakfire_config_entry* entry = NULL; +int pakfire_config_has_section(struct pakfire_config* config, const char* name) { + struct pakfire_config_section* section = NULL; - STAILQ_FOREACH(entry, &config->entries, nodes) { - if (strcmp(entry->section, section) == 0) - return 1; - } + // Fetch the section + section = pakfire_config_get_section(config, name); + if (section) + return 1; return 0; } @@ -540,25 +604,30 @@ static int pakfire_config_dump_entry(struct pakfire_config_entry* entry, FILE* f } static int pakfire_config_dump_section(struct pakfire_config* config, - const char* section, FILE* f) { + const char* name, void* p) { + struct pakfire_config_section* section = NULL; struct pakfire_config_entry* entry = NULL; int r = 0; + FILE* f = (FILE*)p; + + // Fetch the section + section = pakfire_config_get_section(config, name); + if (!section) + return -errno; + // Print the section name - if (*section) { - r = fprintf(f, "\n[%s]\n", section); + if (*name) { + r = fprintf(f, "\n[%s]\n", name); if (r <= 0) goto ERROR; } // Iterate over all entries - STAILQ_FOREACH(entry, &config->entries, nodes) { - // Dump all entries that match this section - if (strcmp(entry->section, section) == 0) { - r = pakfire_config_dump_entry(entry, f); - if (r) - goto ERROR; - } + STAILQ_FOREACH(entry, §ion->entries, nodes) { + r = pakfire_config_dump_entry(entry, f); + if (r) + goto ERROR; } // Success @@ -569,28 +638,5 @@ ERROR: } int pakfire_config_dump(struct pakfire_config* config, FILE* f) { - int r; - - // Fetch a list of all available sections - const char** sections = pakfire_config_sections(config); - - // Dump the default section - r = pakfire_config_dump_section(config, "", f); - if (r) - goto ERROR; - - // Dump all sections - if (sections) { - for (const char** section = sections; *section; section++) { - r = pakfire_config_dump_section(config, *section, f); - if (r) - goto ERROR; - } - } - -ERROR: - if (sections) - free(sections); - - return r; + return pakfire_config_walk_sections(config, pakfire_config_dump_section, f); } diff --git a/src/libpakfire/include/pakfire/config.h b/src/libpakfire/include/pakfire/config.h index 9fca5c8f8..aeea5e7ef 100644 --- a/src/libpakfire/include/pakfire/config.h +++ b/src/libpakfire/include/pakfire/config.h @@ -47,7 +47,12 @@ size_t pakfire_config_get_bytes(struct pakfire_config* config, FILE* pakfire_config_get_fopen(struct pakfire_config* config, const char* section, const char* key); -const char** pakfire_config_sections(struct pakfire_config* config); +// Walk +typedef int (*pakfire_config_walk_callback) + (struct pakfire_config* config, const char* name, void* p); +int pakfire_config_walk_sections(struct pakfire_config* config, + pakfire_config_walk_callback callback, void* p); + int pakfire_config_has_section(struct pakfire_config* config, const char* section); int pakfire_config_read(struct pakfire_config* config, FILE* f); diff --git a/src/libpakfire/repo.c b/src/libpakfire/repo.c index e26d8c724..eb948a3cd 100644 --- a/src/libpakfire/repo.c +++ b/src/libpakfire/repo.c @@ -229,90 +229,92 @@ ERROR: return r; } -int pakfire_repo_import(struct pakfire* pakfire, struct pakfire_config* config) { - const char** sections = pakfire_config_sections(config); - - // The configuration seems to be empty - if (!sections) - return 0; - +static int __pakfire_repo_import( struct pakfire_config* config, const char* section, void* p) { + struct pakfire* pakfire = (struct pakfire*)p; struct pakfire_repo* repo = NULL; int r = 0; - // Walk through all sections - for (const char** section = sections; *section; section++) { - // Skip sections that do not start with "repo:" - if (!pakfire_string_startswith(*section, "repo:")) - continue; + // Ignore if the section does not start with "repo:" + if (!pakfire_string_startswith(section, "repo:")) + return 0; - const char* name = (*section) + strlen("repo:"); - if (!*name) - continue; + // Extract the name + const char* name = section + strlen("repo:"); - DEBUG(pakfire, "Creating repository %s\n", name); + // Skip if the name is empty + if (!*name) + return 0; - // Create a new repository - r = pakfire_repo_create(&repo, pakfire, name); - if (r) { - ERROR(pakfire, "Could not create repository '%s': %m\n", name); - goto ERROR; - } + DEBUG(pakfire, "Creating repository %s\n", name); - // Enabled - int enabled = pakfire_config_get_bool(config, *section, "enabled", 1); - pakfire_repo_set_enabled(repo, enabled); + // Create a new repository + r = pakfire_repo_create(&repo, pakfire, name); + if (r) { + ERROR(pakfire, "Could not create repository '%s': %m\n", name); + goto ERROR; + } - // Priority - int priority = pakfire_config_get_int(config, *section, "priority", 0); - if (priority) - pakfire_repo_set_priority(repo, priority); + // Enabled + int enabled = pakfire_config_get_bool(config, section, "enabled", 1); + pakfire_repo_set_enabled(repo, enabled); - // Description - const char* description = pakfire_config_get(config, *section, "description", NULL); - if (description) - pakfire_repo_set_description(repo, description); + // Priority + int priority = pakfire_config_get_int(config, section, "priority", 0); + if (priority) + pakfire_repo_set_priority(repo, priority); - // baseurl - const char* baseurl = pakfire_config_get(config, *section, "baseurl", NULL); - if (baseurl) { - r = pakfire_repo_set_baseurl(repo, baseurl); - if (r) - goto ERROR; - } + // Description + const char* description = pakfire_config_get(config, section, "description", NULL); + if (description) + pakfire_repo_set_description(repo, description); - // Refresh Interval - const char* refresh = pakfire_config_get(config, *section, "refresh", NULL); - if (refresh) - repo->appdata->refresh = pakfire_string_parse_interval(refresh); + // baseurl + const char* baseurl = pakfire_config_get(config, section, "baseurl", NULL); + if (baseurl) { + r = pakfire_repo_set_baseurl(repo, baseurl); + if (r) + goto ERROR; + } - // mirrors - const char* mirrors = pakfire_config_get(config, *section, "mirrors", NULL); - if (mirrors) - pakfire_repo_set_mirrorlist_url(repo, mirrors); + // Refresh Interval + const char* refresh = pakfire_config_get(config, section, "refresh", NULL); + if (refresh) + repo->appdata->refresh = pakfire_string_parse_interval(refresh); - // Key - const char* key = pakfire_config_get(config, *section, "key", NULL); - if (key) { - r = pakfire_repo_import_key(repo, key); - if (r) { - pakfire_repo_unref(repo); - goto ERROR; - } - } + // mirrors + const char* mirrors = pakfire_config_get(config, section, "mirrors", NULL); + if (mirrors) + pakfire_repo_set_mirrorlist_url(repo, mirrors); - pakfire_repo_unref(repo); + // Key + const char* key = pakfire_config_get(config, section, "key", NULL); + if (key) { + r = pakfire_repo_import_key(repo, key); + if (r) + goto ERROR; } +ERROR: + if (repo) + pakfire_repo_unref(repo); + + return r; +} + +int pakfire_repo_import(struct pakfire* pakfire, struct pakfire_config* config) { + int r; + + // Import all repositories from the configuration + r = pakfire_config_walk_sections(config, __pakfire_repo_import, pakfire); + if (r) + return r; + // Refresh repositories r = pakfire_refresh(pakfire, 0); if (r) - goto ERROR; - -ERROR: - if (sections) - free(sections); + return r; - return r; + return 0; } Id pakfire_repo_add_solvable(struct pakfire_repo* repo) { diff --git a/tests/libpakfire/config.c b/tests/libpakfire/config.c index 946fd2ba9..de2493e25 100644 --- a/tests/libpakfire/config.c +++ b/tests/libpakfire/config.c @@ -122,6 +122,7 @@ static int test_parse(const struct test* t) { // Check for a non-existant key ASSERT(pakfire_config_get_bytes(config, "bytes", "keyXX", 123) == 123); +#if 0 // Get sections char** sections = pakfire_config_sections(config); ASSERT(sections); @@ -138,6 +139,7 @@ static int test_parse(const struct test* t) { ASSERT_STRING_EQUALS(sections[1], "section2"); ASSERT_STRING_EQUALS(sections[2], "bytes"); ASSERT_NULL(sections[3]); +#endif // Everything passed r = EXIT_SUCCESS;