[pacman-dev] [PATCH 2/9] conf: do batch processing of repo sections

Dan McGee dan at archlinux.org
Wed Jun 8 03:51:45 EDT 2011


We now parse an entire repo section and store all information about it.
When the next section is encountered or the end of the root config file
is reached, we will then process the stored information.

Signed-off-by: Dan McGee <dan at archlinux.org>
---
 src/pacman/conf.c |  149 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 100 insertions(+), 49 deletions(-)

diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index 68fe59c..a5bc148 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -507,20 +507,93 @@ static int setup_libalpm(void)
 	return 0;
 }
 
+/**
+ * Allows parsing in advance of an entire config section before we start
+ * calling library methods.
+ */
+struct section_t {
+	/* useful for all sections */
+	char *name;
+	int is_options;
+	/* db section option gathering */
+	pgp_verify_t sigverify;
+	alpm_list_t *servers;
+};
+
+/**
+ * Wrap up a section once we have reached the end of it. This should be called
+ * when a subsequent section is encountered, or when we have reached the end of
+ * the root config file. Once called, all existing saved config pieces on the
+ * section struct are freed.
+ * @param section the current parsed and saved section data
+ * @param parse_options whether we are parsing options or repo data
+ * @return 0 on success, 1 on failure
+ */
+static int finish_section(struct section_t *section, int parse_options)
+{
+	int ret = 0;
+	alpm_list_t *i;
+	pmdb_t *db;
+
+	pm_printf(PM_LOG_DEBUG, "config: finish section '%s'\n", section->name);
+
+	/* parsing options (or nothing)- nothing to do except free the pieces */
+	if(!section->name || parse_options || section->is_options) {
+		goto cleanup;
+	}
+
+	/* if we are not looking at options sections only, register a db */
+	db = alpm_db_register_sync(config->handle, section->name);
+	if(db == NULL) {
+		pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"),
+				section->name, alpm_strerror(alpm_errno(config->handle)));
+		ret = 1;
+		goto cleanup;
+	}
+
+	if(section->sigverify) {
+		if(alpm_db_set_pgp_verify(db, section->sigverify)) {
+			pm_printf(PM_LOG_ERROR,
+					_("could not set verify option for database '%s' (%s)\n"),
+					section->name, alpm_strerror(alpm_errno(config->handle)));
+			ret = 1;
+			goto cleanup;
+		}
+	}
+
+	for(i = section->servers; i; i = alpm_list_next(i)) {
+		char *value = alpm_list_getdata(i);
+		if(_add_mirror(db, value) != 0) {
+			pm_printf(PM_LOG_ERROR,
+					_("could not add mirror '%s' to database '%s' (%s)\n"),
+					value, section->name, alpm_strerror(alpm_errno(config->handle)));
+			ret = 1;
+			goto cleanup;
+		}
+		free(value);
+	}
+
+cleanup:
+	alpm_list_free(section->servers);
+	section->servers = NULL;
+	section->sigverify = 0;
+	free(section->name);
+	section->name = NULL;
+	return ret;
+}
 
 /** The "real" parseconfig. Each "Include" directive will recall this method so
  * recursion and stack depth are limited to 10 levels. The publicly visible
  * parseconfig calls this with a NULL section argument so we can recall from
  * within ourself on an include.
  * @param file path to the config file
- * @param section the current active section name; should be freed after all
- * parsing is complete
- * @param db the current active alpm database object
+ * @param section the current active section
  * @param parse_options whether to parse and call methods for the options
  * section; if 0, parse and call methods for the repos sections
  * @param depth the current recursion depth
- **/
-static int _parseconfig(const char *file, char **section, pmdb_t *db,
+ * @return 0 on success, 1 on failure
+ */
+static int _parseconfig(const char *file, struct section_t *section,
 		int parse_options, int depth)
 {
 	FILE *fp = NULL;
@@ -560,14 +633,6 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 			*ptr = '\0';
 		}
 
-		/* sanity check */
-		if(parse_options && db) {
-			pm_printf(PM_LOG_ERROR, _("config file %s, line %d: parsing options but have a database.\n"),
-						file, linenum);
-			ret = 1;
-			goto cleanup;
-		}
-
 		if(line[0] == '[' && line[line_len - 1] == ']') {
 			char *name;
 			/* only possibility here is a line == '[]' */
@@ -580,21 +645,14 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 			/* new config section, skip the '[' */
 			name = strdup(line + 1);
 			name[line_len - 2] = '\0';
-			pm_printf(PM_LOG_DEBUG, "config: new section '%s'\n", name);
-			/* if we are not looking at the options section, register a db */
-			if(!parse_options && strcmp(name, "options") != 0) {
-				db = alpm_db_register_sync(config->handle, name);
-				if(db == NULL) {
-					pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"),
-							name, alpm_strerror(alpm_errno(config->handle)));
-					ret = 1;
-					goto cleanup;
-				}
-			}
-			if(*section) {
-				free(*section);
+			/* we're at a new section; perform any post-actions for the prior */
+			if(finish_section(section, parse_options)) {
+				ret = 1;
+				goto cleanup;
 			}
-			*section = name;
+			pm_printf(PM_LOG_DEBUG, "config: new section '%s'\n", name);
+			section->name = name;
+			section->is_options = (strcmp(name, "options") == 0);
 			continue;
 		}
 
@@ -613,7 +671,7 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 			goto cleanup;
 		}
 		/* For each directive, compare to the camelcase string. */
-		if(*section == NULL) {
+		if(section->name == NULL) {
 			pm_printf(PM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"),
 					file, linenum);
 			ret = 1;
@@ -653,19 +711,19 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 					for(gindex = 0; gindex < globbuf.gl_pathc; gindex++) {
 						pm_printf(PM_LOG_DEBUG, "config file %s, line %d: including %s\n",
 								file, linenum, globbuf.gl_pathv[gindex]);
-						_parseconfig(globbuf.gl_pathv[gindex], section, db, parse_options, depth++);
+						_parseconfig(globbuf.gl_pathv[gindex], section, parse_options, depth + 1);
 					}
 				break;
 			}
 			globfree(&globbuf);
 			continue;
 		}
-		if(parse_options && strcmp(*section, "options") == 0) {
+		if(parse_options && section->is_options) {
 			/* we are either in options ... */
 			if((ret = _parse_options(key, value, file, linenum)) != 0) {
 				goto cleanup;
 			}
-		} else if (!parse_options && strcmp(*section, "options") != 0) {
+		} else if (!parse_options && !section->is_options) {
 			/* ... or in a repo section */
 			if(strcmp(key, "Server") == 0) {
 				if(value == NULL) {
@@ -674,19 +732,11 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 					ret = 1;
 					goto cleanup;
 				}
-				if(_add_mirror(db, value) != 0) {
-					ret = 1;
-					goto cleanup;
-				}
+				section->servers = alpm_list_add(section->servers, strdup(value));
 			} else if(strcmp(key, "VerifySig") == 0) {
 				pgp_verify_t level = option_verifysig(value);
 				if(level != PM_PGP_VERIFY_UNKNOWN) {
-					ret = alpm_db_set_pgp_verify(db, level);
-					if(ret != 0) {
-						pm_printf(PM_LOG_ERROR, _("could not add set verify option for database '%s': %s (%s)\n"),
-								alpm_db_get_name(db), value, alpm_strerror(alpm_errno(config->handle)));
-						goto cleanup;
-					}
+					section->sigverify = level;
 				} else {
 					pm_printf(PM_LOG_ERROR,
 							_("config file %s, line %d: directive '%s' has invalid value '%s'\n"),
@@ -697,11 +747,15 @@ static int _parseconfig(const char *file, char **section, pmdb_t *db,
 			} else {
 				pm_printf(PM_LOG_WARNING,
 						_("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"),
-						file, linenum, key, *section);
+						file, linenum, key, section->name);
 			}
 		}
 	}
 
+	if(depth == 0) {
+		ret = finish_section(section, parse_options);
+	}
+
 cleanup:
 	fclose(fp);
 	pm_printf(PM_LOG_DEBUG, "config: finished parsing %s\n", file);
@@ -715,26 +769,23 @@ cleanup:
 int parseconfig(const char *file)
 {
 	int ret;
-	char *section = NULL;
+	struct section_t section;
+	memset(&section, 0, sizeof(struct section_t));
 	/* the config parse is a two-pass affair. We first parse the entire thing for
 	 * the [options] section so we can get all default and path options set.
 	 * Next, we go back and parse everything but [options]. */
 
 	/* call the real parseconfig function with a null section & db argument */
 	pm_printf(PM_LOG_DEBUG, "parseconfig: options pass\n");
-	if((ret = _parseconfig(file, &section, NULL, 1, 0))) {
-		free(section);
+	if((ret = _parseconfig(file, &section, 1, 0))) {
 		return ret;
 	}
-	free(section);
 	if((ret = setup_libalpm())) {
 		return ret;
 	}
 	/* second pass, repo section parsing */
-	section = NULL;
 	pm_printf(PM_LOG_DEBUG, "parseconfig: repo pass\n");
-	return _parseconfig(file, &section, NULL, 0, 0);
-	free(section);
+	return _parseconfig(file, &section, 0, 0);
 }
 
 /* vim: set ts=2 sw=2 noet: */
-- 
1.7.5.2



More information about the pacman-dev mailing list