aboutsummaryrefslogtreecommitdiff
path: root/libpkgconf/dependency.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpkgconf/dependency.c')
-rw-r--r--libpkgconf/dependency.c94
1 files changed, 80 insertions, 14 deletions
diff --git a/libpkgconf/dependency.c b/libpkgconf/dependency.c
index cd01a06..b3722b1 100644
--- a/libpkgconf/dependency.c
+++ b/libpkgconf/dependency.c
@@ -52,11 +52,76 @@ dependency_to_str(const pkgconf_dependency_t *dep, char *buf, size_t buflen)
return buf;
}
+/* find a colliding dependency that is coloured differently */
static inline pkgconf_dependency_t *
-pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, size_t package_sz, const char *version, size_t version_sz, pkgconf_pkg_comparator_t compare)
+find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t *list)
+{
+ const pkgconf_node_t *n;
+
+ PKGCONF_FOREACH_LIST_ENTRY(list->head, n)
+ {
+ pkgconf_dependency_t *dep2 = n->data;
+
+ if (strcmp(dep->package, dep2->package))
+ continue;
+
+ if (dep->flags != dep2->flags)
+ return dep2;
+ }
+
+ return NULL;
+}
+
+static inline pkgconf_dependency_t *
+add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list)
{
- pkgconf_dependency_t *dep;
char depbuf[PKGCONF_ITEM_SIZE];
+ pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list);
+
+ /* there is already a node in the graph which describes this dependency */
+ if (dep2 != NULL)
+ {
+ char depbuf2[PKGCONF_ITEM_SIZE];
+
+ PKGCONF_TRACE(client, "dependency collision: [%s/%x] -- [%s/%x]",
+ dependency_to_str(dep, depbuf, sizeof depbuf), dep->flags,
+ dependency_to_str(dep2, depbuf2, sizeof depbuf2), dep2->flags);
+
+ /* prefer the uncoloured node, either dep or dep2 */
+ if (dep->flags && dep2->flags == 0)
+ {
+ PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf, dep);
+
+ free(dep);
+ return NULL;
+ }
+ else if (dep2->flags && dep->flags == 0)
+ {
+ PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf2, dep2);
+
+ pkgconf_node_delete(&dep2->iter, list);
+ free(dep2);
+ }
+ else
+ /* If both dependencies have equal strength, we keep both, because of situations like:
+ * Requires: foo > 1, foo < 3
+ *
+ * If the situation is that both dependencies are literally equal, it is still harmless because
+ * fragment deduplication will handle the excessive fragments.
+ */
+ PKGCONF_TRACE(client, "keeping both dependencies (harmless)");
+ }
+
+ PKGCONF_TRACE(client, "added dependency [%s] to list @%p; flags=%x", dependency_to_str(dep, depbuf, sizeof depbuf), list, dep->flags);
+ pkgconf_node_insert_tail(&dep->iter, dep, list);
+
+ return dep;
+}
+
+static inline pkgconf_dependency_t *
+pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, size_t package_sz, const char *version, size_t version_sz, pkgconf_pkg_comparator_t compare, unsigned int flags)
+{
+ pkgconf_dependency_t *dep;
dep = calloc(sizeof(pkgconf_dependency_t), 1);
dep->package = pkgconf_strndup(package, package_sz);
@@ -65,11 +130,9 @@ pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list,
dep->version = pkgconf_strndup(version, version_sz);
dep->compare = compare;
+ dep->flags = flags;
- PKGCONF_TRACE(client, "added dependency [%s] to list @%p", dependency_to_str(dep, depbuf, sizeof depbuf), list);
- pkgconf_node_insert_tail(&dep->iter, dep, list);
-
- return dep;
+ return add_or_replace_dependency_node(client, dep, list);
}
/*
@@ -84,16 +147,17 @@ pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list,
* :param char* package: The package `atom` to set on the dependency node.
* :param char* version: The package `version` to set on the dependency node.
* :param pkgconf_pkg_comparator_t compare: The comparison operator to set on the dependency node.
+ * :param uint flags: Any flags to attach to the dependency node.
* :return: A dependency node.
* :rtype: pkgconf_dependency_t *
*/
pkgconf_dependency_t *
-pkgconf_dependency_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare)
+pkgconf_dependency_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags)
{
if (version != NULL)
- return pkgconf_dependency_addraw(client, list, package, strlen(package), version, strlen(version), compare);
+ return pkgconf_dependency_addraw(client, list, package, strlen(package), version, strlen(version), compare, flags);
- return pkgconf_dependency_addraw(client, list, package, strlen(package), NULL, 0, compare);
+ return pkgconf_dependency_addraw(client, list, package, strlen(package), NULL, 0, compare, flags);
}
/*
@@ -157,10 +221,11 @@ pkgconf_dependency_free(pkgconf_list_t *list)
* :param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
* :param pkgconf_list_t* deplist_head: The dependency list to populate with dependency nodes.
* :param char* depends: The dependency data to parse.
+ * :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing
*/
void
-pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends)
+pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags)
{
parse_state_t state = OUTSIDE_MODULE;
pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY;
@@ -227,7 +292,7 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
if (state == OUTSIDE_MODULE)
{
- pkgconf_dependency_addraw(client, deplist_head, package, package_sz, NULL, 0, compare);
+ pkgconf_dependency_addraw(client, deplist_head, package, package_sz, NULL, 0, compare, flags);
compare = PKGCONF_CMP_ANY;
package_sz = 0;
@@ -270,7 +335,7 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
version_sz = ptr - vstart;
state = OUTSIDE_MODULE;
- pkgconf_dependency_addraw(client, deplist_head, package, package_sz, version, version_sz, compare);
+ pkgconf_dependency_addraw(client, deplist_head, package, package_sz, version, version_sz, compare, flags);
compare = PKGCONF_CMP_ANY;
cnameptr = cmpname;
@@ -300,13 +365,14 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
* :param pkgconf_pkg_t* pkg: The package object that owns this dependency list.
* :param pkgconf_list_t* deplist: The dependency list to populate with dependency nodes.
* :param char* depends: The dependency data to parse.
+ * :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing
*/
void
-pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends)
+pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags)
{
char *kvdepends = pkgconf_tuple_parse(client, &pkg->vars, depends);
- pkgconf_dependency_parse_str(client, deplist, kvdepends);
+ pkgconf_dependency_parse_str(client, deplist, kvdepends, flags);
free(kvdepends);
}