[pacman-dev] [PATCH] Allow version bounds in IgnorePkg entries

Daniel Schoepe daniel at schoepe.org
Mon Jun 29 15:35:41 UTC 2015


This patch adds support for ignoring specific version of packages in
IgnorePkg. This is useful for ignoring a version that is known to be
buggy where a fix is going to be included in the next version. Only
equality comparisons (e.g. "foo=1.0-1" or "bar=1.0") are supported.

Signed-off-by: Daniel Schoepe <daniel at schoepe.org>
---
 NEWS                           |  2 +
 doc/pacman.conf.5.txt          |  4 +-
 lib/libalpm/alpm.h             |  4 +-
 lib/libalpm/handle.c           | 97 +++++++++++++++++++++++++-----------------
 lib/libalpm/package.c          | 27 ++++++++++--
 src/pacman/conf.c              | 62 ++++++++++++++++++++-------
 test/pacman/tests/TESTS        |  5 +++
 test/pacman/tests/ignore009.py | 14 ++++++
 test/pacman/tests/ignore010.py | 13 ++++++
 test/pacman/tests/ignore011.py | 13 ++++++
 test/pacman/tests/ignore012.py | 13 ++++++
 test/pacman/tests/ignore013.py | 13 ++++++
 12 files changed, 205 insertions(+), 62 deletions(-)
 create mode 100644 test/pacman/tests/ignore009.py
 create mode 100644 test/pacman/tests/ignore010.py
 create mode 100644 test/pacman/tests/ignore011.py
 create mode 100644 test/pacman/tests/ignore012.py
 create mode 100644 test/pacman/tests/ignore013.py

diff --git a/NEWS b/NEWS
index a4d3dba..f42a185 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ VERSION         DESCRIPTION
 5.0.0         - pacman can check the validity of the local and sync databases
                 (-Dk and -Dkk respectively).  This replaces the 'testdb'
                 software
+              - pacman supports specific version bounds on packages in
+                IgnorePkg.
 4.2.1         - Remove warnings about incorrect directory ownership until
                 packaging files with dynamic users/groups is improved
               - Do not require a specific automake version when building from
diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt
index 383e072..2e29ad0 100644
--- a/doc/pacman.conf.5.txt
+++ b/doc/pacman.conf.5.txt
@@ -92,7 +92,9 @@ Options
 
 *IgnorePkg =* package ...::
 	Instructs pacman to ignore any upgrades for this package when performing
-	a '\--sysupgrade'. Shell-style glob patterns are allowed.
+	a '\--sysupgrade'. Shell-style glob patterns are allowed. Specific
+	package versions can be ignored; for example 'foo=1.0' ignores only
+	updates to version 1.0 of foo.
 
 *IgnoreGroup =* group ...::
 	Instructs pacman to ignore any upgrades for all packages in this
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 06e080b..34753b0 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -821,9 +821,9 @@ int alpm_option_match_noextract(alpm_handle_t *handle, const char *path);
  * @{
  */
 alpm_list_t *alpm_option_get_ignorepkgs(alpm_handle_t *handle);
-int alpm_option_add_ignorepkg(alpm_handle_t *handle, const char *pkg);
+int alpm_option_add_ignorepkg(alpm_handle_t *handle, const alpm_depend_t *pkg);
 int alpm_option_set_ignorepkgs(alpm_handle_t *handle, alpm_list_t *ignorepkgs);
-int alpm_option_remove_ignorepkg(alpm_handle_t *handle, const char *pkg);
+int alpm_option_remove_ignorepkg(alpm_handle_t *handle, const alpm_depend_t *pkg);
 /** @} */
 
 /** @name Accessors to the list of ignored groups.
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 4915d0b..9980201 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -88,7 +88,8 @@ void _alpm_handle_free(alpm_handle_t *handle)
 	FREE(handle->gpgdir);
 	FREELIST(handle->noupgrade);
 	FREELIST(handle->noextract);
-	FREELIST(handle->ignorepkg);
+	alpm_list_free_inner(handle->ignorepkg, (alpm_list_fn_free)alpm_dep_free);
+	alpm_list_free(handle->ignorepkg);
 	FREELIST(handle->ignoregroup);
 
 	alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
@@ -512,6 +513,54 @@ static int _alpm_option_strlist_rem(alpm_handle_t *handle, alpm_list_t **list, c
 	return 0;
 }
 
+/* Note that, at the moment, the following functions don't copy their
+   arguments like the _strlist equivalents do. */
+static int _alpm_option_deplist_add(alpm_handle_t *handle, alpm_list_t **list, const alpm_depend_t *dep)
+{
+	CHECK_HANDLE(handle, return -1);
+	*list = alpm_list_add(*list, (void *)dep);
+	return 0;
+}
+
+static int _alpm_option_deplist_set(alpm_handle_t *handle, alpm_list_t **list, alpm_list_t *newlist)
+{
+	CHECK_HANDLE(handle, return -1);
+	if(list) {
+		alpm_list_free_inner(*list, (alpm_list_fn_free)alpm_dep_free);
+		alpm_list_free(*list);
+	}
+	*list = newlist;
+	return 0;
+}
+
+static int depend_cmp(const void *d1, const void *d2)
+{
+	const alpm_depend_t *dep1 = d1;
+	const alpm_depend_t *dep2 = d2;
+
+	if(strcmp(dep1->name, dep2->name) == 0 &&
+	   strcmp(dep1->version, dep2->version) == 0 &&
+	   dep1->mod == dep2->mod) {
+		return 0;
+	}
+
+	return -1;
+}
+
+static int _alpm_option_deplist_rem(alpm_handle_t *handle, alpm_list_t **list, const alpm_depend_t *dep)
+{
+	alpm_depend_t *vdata = NULL;
+	CHECK_HANDLE(handle, return -1);
+
+	*list = alpm_list_remove(handle->assumeinstalled, dep, &depend_cmp, (void **)&vdata);
+	if(vdata != NULL) {
+		alpm_dep_free(vdata);
+		return 1;
+	}
+
+	return 0;
+}
+
 int SYMEXPORT alpm_option_add_noupgrade(alpm_handle_t *handle, const char *pkg)
 {
 	return _alpm_option_strlist_add(handle, &(handle->noupgrade), pkg);
@@ -552,19 +601,19 @@ int SYMEXPORT alpm_option_match_noextract(alpm_handle_t *handle, const char *pat
 	return _alpm_fnmatch_patterns(handle->noextract, path);
 }
 
-int SYMEXPORT alpm_option_add_ignorepkg(alpm_handle_t *handle, const char *pkg)
+int SYMEXPORT alpm_option_add_ignorepkg(alpm_handle_t *handle, const alpm_depend_t *pkg)
 {
-	return _alpm_option_strlist_add(handle, &(handle->ignorepkg), pkg);
+	return _alpm_option_deplist_add(handle, &(handle->ignorepkg), pkg);
 }
 
 int SYMEXPORT alpm_option_set_ignorepkgs(alpm_handle_t *handle, alpm_list_t *ignorepkgs)
 {
-	return _alpm_option_strlist_set(handle, &(handle->ignorepkg), ignorepkgs);
+	return _alpm_option_deplist_set(handle, &(handle->ignorepkg), ignorepkgs);
 }
 
-int SYMEXPORT alpm_option_remove_ignorepkg(alpm_handle_t *handle, const char *pkg)
+int SYMEXPORT alpm_option_remove_ignorepkg(alpm_handle_t *handle, const alpm_depend_t *pkg)
 {
-	return _alpm_option_strlist_rem(handle, &(handle->ignorepkg), pkg);
+	return _alpm_option_deplist_rem(handle, &(handle->ignorepkg), pkg);
 }
 
 int SYMEXPORT alpm_option_add_ignoregroup(alpm_handle_t *handle, const char *grp)
@@ -584,47 +633,17 @@ int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *
 
 int SYMEXPORT alpm_option_add_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
 {
-	CHECK_HANDLE(handle, return -1);
-
-	handle->assumeinstalled = alpm_list_add(handle->assumeinstalled, (void *)dep);
-	return 0;
+	return _alpm_option_deplist_add(handle, &(handle->assumeinstalled), dep);
 }
 
 int SYMEXPORT alpm_option_set_assumeinstalled(alpm_handle_t *handle, alpm_list_t *deps)
 {
-	CHECK_HANDLE(handle, return -1);
-	if(handle->assumeinstalled) {
-		alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
-		alpm_list_free(handle->assumeinstalled);
-	}
-	handle->assumeinstalled = deps;
-	return 0;
-}
-
-static int assumeinstalled_cmp(const void *d1, const void *d2)
-{
-	const alpm_depend_t *dep1 = d1;
-	const alpm_depend_t *dep2 = d2;
-
-	if(strcmp(dep1->name, dep2->name) == 0 && strcmp(dep1->version, dep2->version) == 0) {
-		return 0;
-	}
-
-	return -1;
+	return _alpm_option_deplist_set(handle, &(handle->assumeinstalled), deps);
 }
 
 int SYMEXPORT alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
 {
-	alpm_depend_t *vdata = NULL;
-	CHECK_HANDLE(handle, return -1);
-
-	handle->assumeinstalled = alpm_list_remove(handle->assumeinstalled, dep, &assumeinstalled_cmp, (void **)&vdata);
-	if(vdata != NULL) {
-		alpm_dep_free(vdata);
-		return 1;
-	}
-
-	return 0;
+	return _alpm_option_deplist_rem(handle, &(handle->assumeinstalled), dep);
 }
 
 int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch)
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 4b5120b..ac27cab 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -768,10 +768,29 @@ alpm_pkg_t SYMEXPORT *alpm_pkg_find(alpm_list_t *haystack, const char *needle)
 int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)
 {
 	alpm_list_t *groups = NULL;
-
-	/* first see if the package is ignored */
-	if(alpm_list_find(handle->ignorepkg, pkg->name, _alpm_fnmatch)) {
-		return 1;
+	alpm_list_t *pkgs = NULL;
+
+	/* first see if package is matched by IgnorePkg */
+	for(pkgs = handle->ignorepkg; pkgs; pkgs = pkgs->next) {
+		alpm_depend_t *ignored = pkgs->data;
+		char *oldname = NULL;
+		/* check names using fnmatch first: */
+		if(strcmp(ignored->name, pkg->name) != 0 &&
+			 _alpm_fnmatch(ignored->name, pkg->name) == 0) {
+			oldname = ignored->name;
+			/* If the name matched a glob expression, replace the pattern by
+				 the concrete name for the version comparison to work. */
+			ignored->name = strdup(pkg->name);
+			ignored->name_hash = _alpm_hash_sdbm(pkg->name);
+		}
+		int result = _alpm_depcmp_literal(pkg, ignored);
+		if(oldname != NULL) {
+			/* Restore the original glob expression. */
+			ignored->name = oldname;
+		}
+		if(result) {
+			return 1;
+		}
 	}
 
 	/* next see if the package is in a group that is ignored */
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index ccf8183..177ff86 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -677,6 +677,42 @@ static int register_repo(config_repo_t *repo)
 	return 0;
 }
 
+typedef int (*add_fn)(alpm_handle_t *, const alpm_depend_t *);
+static int _add_dep_list(alpm_handle_t *handle, alpm_list_t *list, add_fn add,
+		const char *name)
+{
+	int ret;
+	for(; list; list = list->next) {
+		char *entry = list->data;
+		alpm_depend_t *dep = alpm_dep_from_string(entry);
+		if(!dep) {
+			return 1;
+		}
+		pm_printf(ALPM_LOG_DEBUG, "parsed %s: %s %s\n", name, dep->name,
+				dep->version);
+
+		ret = (*add)(handle, dep);
+		if(ret != 0) {
+			pm_printf(ALPM_LOG_ERROR, _("Failed to pass %s entry to libalpm\n"),
+					name);
+			alpm_dep_free(dep);
+			return ret;
+		}
+	}
+	return 0;
+}
+/* This is basically alpm_option_add_ignorepkg with an extra sanity
+ * check. */
+static int _add_ignorepkg(alpm_handle_t *handle, const alpm_depend_t *dep)
+{
+	if (dep->mod != ALPM_DEP_MOD_ANY && dep->mod != ALPM_DEP_MOD_EQ) {
+		pm_printf(ALPM_LOG_ERROR, "Invalid version constraint in IgnorePkg: %s",
+				dep->name);
+		return 1;
+	}
+	return alpm_option_add_ignorepkg(handle, dep);
+}
+
 /** Sets up libalpm global stuff in one go. Called after the command line
  * and initial config file parsing. Once this is complete, we can see if any
  * paths were defined. If a rootdir was defined and nothing else, we want all
@@ -783,26 +819,20 @@ static int setup_libalpm(void)
 	alpm_option_set_usesyslog(handle, config->usesyslog);
 	alpm_option_set_deltaratio(handle, config->deltaratio);
 
-	alpm_option_set_ignorepkgs(handle, config->ignorepkg);
 	alpm_option_set_ignoregroups(handle, config->ignoregrp);
 	alpm_option_set_noupgrades(handle, config->noupgrade);
 	alpm_option_set_noextracts(handle, config->noextract);
 
-	for(i = config->assumeinstalled; i; i = i->next) {
-		char *entry = i->data;
-		alpm_depend_t *dep = alpm_dep_from_string(entry);
-		if(!dep) {
-			return 1;
-		}
-		pm_printf(ALPM_LOG_DEBUG, "parsed assume installed: %s %s\n", dep->name, dep->version);
-
-		ret = alpm_option_add_assumeinstalled(handle, dep);
-		if(ret) {
-			pm_printf(ALPM_LOG_ERROR, _("Failed to pass %s entry to libalpm"), "assume-installed");
-			alpm_dep_free(dep);
-			return ret;
-		}
-	 }
+	ret = _add_dep_list(handle, config->assumeinstalled,
+			&alpm_option_add_assumeinstalled, "assume-installed");
+	if(ret != 0) {
+		return ret;
+	}
+	ret = _add_dep_list(handle, config->ignorepkg, &_add_ignorepkg,
+			"ignorepkg");
+	if(ret != 0) {
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
index 3ff0b0c..fd9999c 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -57,6 +57,11 @@ TESTS += test/pacman/tests/ignore005.py
 TESTS += test/pacman/tests/ignore006.py
 TESTS += test/pacman/tests/ignore007.py
 TESTS += test/pacman/tests/ignore008.py
+TESTS += test/pacman/tests/ignore009.py
+TESTS += test/pacman/tests/ignore010.py
+TESTS += test/pacman/tests/ignore011.py
+TESTS += test/pacman/tests/ignore012.py
+TESTS += test/pacman/tests/ignore013.py
 TESTS += test/pacman/tests/ldconfig001.py
 TESTS += test/pacman/tests/ldconfig002.py
 TESTS += test/pacman/tests/ldconfig003.py
diff --git a/test/pacman/tests/ignore009.py b/test/pacman/tests/ignore009.py
new file mode 100644
index 0000000..52125c8
--- /dev/null
+++ b/test/pacman/tests/ignore009.py
@@ -0,0 +1,14 @@
+self.description = "Sync with specific ignored package version"
+
+package1 = pmpkg("package1", "1.0-1")
+self.addpkg2db("local", package1)
+
+package1up = pmpkg("package1", "1.1-1")
+self.addpkg2db("sync", package1up)
+
+self.option["IgnorePkg"] = ["package1=1.1-1"]
+self.args = "-Su"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_VERSION=package1|1.0-1")
+
diff --git a/test/pacman/tests/ignore010.py b/test/pacman/tests/ignore010.py
new file mode 100644
index 0000000..c96c9de
--- /dev/null
+++ b/test/pacman/tests/ignore010.py
@@ -0,0 +1,13 @@
+self.description = "Sync with invalid bound on IgnorePkg"
+
+package1 = pmpkg("package1", "1.0-1")
+self.addpkg2db("local", package1)
+
+package1up = pmpkg("package1", "1.1-1")
+self.addpkg2db("sync", package1up)
+
+self.option["IgnorePkg"] = ["package1<1.1-1"]
+self.args = "-Su"
+
+self.addrule("PACMAN_RETCODE=0")
+self.expectfailure = True
diff --git a/test/pacman/tests/ignore011.py b/test/pacman/tests/ignore011.py
new file mode 100644
index 0000000..4fae819
--- /dev/null
+++ b/test/pacman/tests/ignore011.py
@@ -0,0 +1,13 @@
+self.description = "Sync with specific ignored, non-matching package version"
+
+package1 = pmpkg("package1", "1.0-1")
+self.addpkg2db("local", package1)
+
+package1up = pmpkg("package1", "1.2-1")
+self.addpkg2db("sync", package1up)
+
+self.option["IgnorePkg"] = ["package1=1.1-1"]
+self.args = "-Su"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_VERSION=package1|1.2-1")
diff --git a/test/pacman/tests/ignore012.py b/test/pacman/tests/ignore012.py
new file mode 100644
index 0000000..ffbcc5e
--- /dev/null
+++ b/test/pacman/tests/ignore012.py
@@ -0,0 +1,13 @@
+self.description = "Sync with ignored package version and fnmatch"
+
+package1 = pmpkg("package1", "1.0-1")
+self.addpkg2db("local", package1)
+
+package1up = pmpkg("package1", "1.1-1")
+self.addpkg2db("sync", package1up)
+
+self.option["IgnorePkg"] = ["packag*=1.1-1"]
+self.args = "-Su"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_VERSION=package1|1.0-1")
diff --git a/test/pacman/tests/ignore013.py b/test/pacman/tests/ignore013.py
new file mode 100644
index 0000000..9a8edfc
--- /dev/null
+++ b/test/pacman/tests/ignore013.py
@@ -0,0 +1,13 @@
+self.description = "Sync with ignored package version without pkgrel"
+
+package1 = pmpkg("package1", "1.0-1")
+self.addpkg2db("local", package1)
+
+package1up = pmpkg("package1", "1.1-1")
+self.addpkg2db("sync", package1up)
+
+self.option["IgnorePkg"] = ["package1=1.1"]
+self.args = "-Su"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_VERSION=package1|1.0-1")
-- 
2.4.4


More information about the pacman-dev mailing list