proj/portage-utils:master commit in: libq/
"Fabian Groffen" <[email protected]>
| Newsgroups | gmane.linux.gentoo.cvs |
|---|---|
| Message-ID | <1782333542.c9ae9f01fd9b68606222f531ec938ff8228b3d40.grobian@gentoo> |
commit: c9ae9f01fd9b68606222f531ec938ff8228b3d40
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Wed Jun 24 20:39:02 2026 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Wed Jun 24 20:39:02 2026 +0000
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c9ae9f01
libq/dep: implement masks, blockers and keywords
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
libq/dep.c | 197 ++++++++++++++++++++++++++++++++++++++++++++-----------------
libq/dep.h | 6 +-
2 files changed, 147 insertions(+), 56 deletions(-)
diff --git a/libq/dep.c b/libq/dep.c
index f05a0b85..c068b743 100644
--- a/libq/dep.c
+++ b/libq/dep.c
@@ -72,8 +72,11 @@ struct dep_node_ {
tree_pkg_ctx *ipkg;
dep_node_t *parent;
array *members;
+ atom_ctx *blockatom;
+ dep_node_t *fail;
dep_type_t type;
bool invert:1;
+ bool inactive:1;
};
dep_node_t *dep_grow_tree
@@ -478,7 +481,8 @@ static void dep_print_tree_int
if (root->pkg != NULL)
{
a = tree_pkg_atom(root->pkg, false);
- if (hlatoms == NULL)
+ if (hlatoms == NULL &&
+ hlcolor != NULL)
match = true;
}
@@ -643,13 +647,18 @@ void dep_prune_use
* can be retrieved using TODO(FIXME)
* - RESOLVE_NEWBLOCKER: like RESOLVE_OK, but a new blocker was added to
* the blockers list, and the caller should re-resolve the full tree
+ * blockers is a hash containing arrays to multiple masks or blockers
+ * can be stored while still allowing to lookup per PN
+ * accept_keywords a set of keywords of which one should match with the
+ * one defined in KEYWORDS for the package
*/
dep_status_t dep_resolve_tree
(
dep_node_t *root,
tree_ctx *tree,
set_t *use,
- hash_t *blockers
+ hash_t *blockers,
+ set_t *accept_keywords
)
{
dep_status_t ret = DEP_OK; /* resolving succeed */
@@ -664,97 +673,140 @@ dep_status_t dep_resolve_tree
{
if (root->atom->blocker != ATOM_BL_NONE)
{
+ array *atoms;
atom_ctx *prevatom;
+ size_t n;
if (blockers == NULL)
break; /* ignore */
- /* add blocker to the list of blockers under CAT/PN:SLOT key */
- blockers = hash_add(blockers,
- atom_format("%[CAT]%[PN]%[SLOT]", root->atom),
- atom_clone(root->atom), (void **)&prevatom);
- ret = DEP_NEWBLOCKER;
+ atoms = hash_get(blockers,
+ atom_format("%[CAT]%[PN]%[SLOT]", root->atom));
+ if (atoms == NULL)
+ {
+ atoms = array_new();
+ hash_add(blockers,
+ atom_format("%[CAT]%[PN]%[SLOT]", root->atom),
+ atoms, NULL /* must be unset */);
+ }
- /* FIXME: this means we have two blockers that cover the same
- * key, which doesn't mean they are the same or that they are
- * compatible, e.g. !foo-1 and !foo-2, how should we handle
- * this? */
- if (prevatom != NULL)
+ ret = DEP_NEWBLOCKER;
+ array_for_each(atoms, n, prevatom)
{
- if (atom_compare(root->atom, prevatom) == EQUAL)
+ /* atom_compare cannot work with blocker or range ops on both
+ * sides, so check the two atoms to be identical instead */
+ if (atom_compare_flg(root->atom, prevatom,
+ (ATOM_COMP_EXACT |
+ ATOM_COMP_NOREPO)) == EQUAL)
+ {
ret = DEP_OK;
- atom_implode(prevatom);
+ break;
+ }
}
+
+ /* add new/different blocker */
+ if (ret == DEP_NEWBLOCKER)
+ array_append(atoms, atom_clone(root->atom));
}
else
{
array *r;
+ array *blkatoms;
atom_ctx *blkatom;
tree_pkg_ctx *pkgw;
size_t n;
+ size_t m;
+ bool ismasked = false;
+ bool isunkeyw = false;
- blkatom = hash_get(blockers,
- atom_format("%[CAT]%[PN]%[SLOT]", root->atom));
+ blkatoms = hash_get(blockers,
+ atom_format("%[CAT]%[PN]%[SLOT]", root->atom));
r = tree_match_atom(tree, root->atom,
(TREE_MATCH_DEFAULT |
- (blkatom == NULL ? TREE_MATCH_LATEST : 0)));
+ TREE_MATCH_SORT));
- if (blkatom != NULL)
+ /* consume from the returned matches the first VDB and non-VDB
+ * that are not covered by masks or keywords */
+ array_for_each(r, n, pkgw)
{
- atom_equality eq;
- array_for_each(r, n, pkgw)
+ atom_ctx *atom = tree_pkg_atom(pkgw, true);
+ char *kwstr;
+ set_t *keywords;
+
+ /* check whether masks apply */
+ ismasked = false;
+ array_for_each(blkatoms, m, blkatom)
{
- eq = atom_compare(tree_pkg_atom(pkgw, true), blkatom);
+ atom_equality eq;
+
+ eq = atom_compare(atom, blkatom);
if (blkatom->blocker != ATOM_BL_NONE) /* blocker */
{
- if (eq == EQUAL)
+ if (eq != EQUAL)
{
- if (root->pkg == NULL)
- root->pkg = pkgw;
- if (tree_pkg_get_treetype(pkgw) == TREETYPE_VDB)
- {
- root->ipkg = pkgw;
- break;
- }
+ ismasked = true;
+ break;
}
}
else /* mask entry */
{
- if (eq == NOT_EQUAL ||
- eq == NEWER)
+ if (eq == EQUAL)
{
- if (root->pkg == NULL)
- root->pkg = pkgw;
- if (tree_pkg_get_treetype(pkgw) == TREETYPE_VDB)
- {
- root->ipkg = pkgw;
- break;
- }
+ ismasked = true;
+ break;
}
}
}
+
+ if (ismasked)
+ continue;
+
+ /* check keywords */
+ kwstr = tree_pkg_meta(pkgw, Q_KEYWORDS);
+ if (kwstr == NULL)
+ {
+ isunkeyw = true;
+ continue;
+ }
+
+ keywords = set_add_from_string(set_new(), kwstr);
+ if (!set_has_intersection(keywords, accept_keywords))
+ {
+ isunkeyw = true;
+ continue;
+ }
+ set_free(keywords);
+
+ /* finally, assign */
if (root->pkg == NULL)
- ret = DEP_FAIL;
+ root->pkg = pkgw;
+ if (tree_pkg_get_treetype(pkgw) == TREETYPE_VDB)
+ {
+ if (root->ipkg == NULL)
+ root->ipkg = pkgw;
+ break;
+ }
+
+ if (root->pkg != NULL &&
+ root->ipkg != NULL)
+ break; /* stop searching, we got 'em */
}
- else
+
+ if (root->pkg == NULL)
{
- root->pkg = array_get(r, 0);
- if (root->pkg != NULL)
+ ret = DEP_FAIL;
+ if (ismasked)
{
- array_for_each(r, n, pkgw)
- {
- if (tree_pkg_get_treetype(pkgw) == TREETYPE_VDB)
- {
- root->ipkg = pkgw;
- break;
- }
- }
+ root->blockatom = blkatom;
+ if (blkatom->blocker == ATOM_BL_NONE)
+ ret = DEP_MASK; /* masked */
}
- else
+ else if (isunkeyw)
{
- ret = DEP_FAIL;
+ ret = DEP_KEYWORD; /* missing keyword */
}
}
+
array_free(r);
}
}
@@ -765,8 +817,11 @@ dep_status_t dep_resolve_tree
* original dep-tree, would not want to see the tree be modified
* (which is what prune_use does) */
if ((!set_contains(use, root->word)) ^ root->invert)
+ {
+ root->inactive = true;
break;
- /* TODO: maybe flag the node as being selected or something? */
+ }
+ root->inactive = false;
/* fall through -- handle as ALL-group */
case DEP_ALL:
if (root->members)
@@ -776,9 +831,13 @@ dep_status_t dep_resolve_tree
array_for_each(root->members, n, memb)
{
- if ((ret = dep_resolve_tree(memb, tree, use, blockers)) != DEP_OK)
+ if ((ret = dep_resolve_tree(memb, tree, use,
+ blockers, accept_keywords)) != DEP_OK)
break;
}
+
+ if (ret != DEP_FAIL)
+ root->fail = memb;
}
break;
case DEP_ANY:
@@ -794,7 +853,8 @@ dep_status_t dep_resolve_tree
ret = DEP_FAIL;
array_for_each(root->members, n, memb)
{
- if ((sret = dep_resolve_tree(memb, tree, use, blockers)) == DEP_FAIL)
+ if ((sret = dep_resolve_tree(memb, tree, use,
+ blockers, accept_keywords)) == DEP_FAIL)
continue;
if (sret == DEP_NEWBLOCKER)
ret = DEP_NEWBLOCKER;
@@ -819,6 +879,7 @@ static void dep_flatten_tree_int
)
{
if (root->type == DEP_NULL ||
+ root->inactive ||
out == NULL)
return;
@@ -903,4 +964,30 @@ atom_ctx *dep_node_atom
return node->atom;
}
+atom_ctx *dep_node_mask
+(
+ dep_node_t *node
+)
+{
+ if (node == NULL)
+ return NULL;
+
+ return node->blockatom;
+}
+
+atom_ctx *dep_node_fail_input
+(
+ dep_node_t *node
+)
+{
+ if (node == NULL)
+ return NULL;
+
+ /* skip over USE */
+ while (node->fail != NULL)
+ node = node->fail;
+
+ return node->atom;
+}
+
/* vim: set ts=2 sw=2 expandtab cino+=\:0 foldmethod=marker: */
diff --git a/libq/dep.h b/libq/dep.h
index 705f9172..3cf6b1dc 100644
--- a/libq/dep.h
+++ b/libq/dep.h
@@ -20,6 +20,8 @@ typedef enum dep_status_ dep_status_t;
enum dep_status_ {
DEP_OK = 1,
DEP_FAIL,
+ DEP_MASK,
+ DEP_KEYWORD,
DEP_NEWBLOCKER,
};
@@ -28,7 +30,7 @@ dep_node_t *dep_grow_tree(const char *depend);
void dep_print_tree(FILE *fp, const dep_node_t *root, size_t space,
array *m, const char *c, int verbose);
dep_status_t dep_resolve_tree(dep_node_t *root, tree_ctx *t,
- set_t *use, hash_t *blockers);
+ set_t *use, hash_t *blockers, set_t *keywords);
void dep_prune_use(dep_node_t *root, set_t *use);
array *dep_flatten_tree(dep_node_t *root);
void dep_burn_tree(dep_node_t *root);
@@ -45,6 +47,8 @@ array *dep_nodes(dep_node_t *node);
tree_pkg_ctx *dep_node_pkg(dep_node_t *node);
tree_pkg_ctx *dep_node_ipkg(dep_node_t *node);
atom_ctx *dep_node_atom(dep_node_t *node);
+atom_ctx *dep_node_mask(dep_node_t *node);
+atom_ctx *dep_node_fail_input(dep_node_t *node);
#endif