1 |
commit: 553eb9afd1a57bbe56bdddd77ddf0bb450ee32b8 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Mon May 25 10:34:54 2020 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Mon May 25 10:34:54 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=553eb9af |
7 |
|
8 |
libq/tree: rework tree_match_atom to return a list of results |
9 |
|
10 |
Major change is that multiple results are returned, somewhat controlled |
11 |
by flags, and that the results are valid until the tree is closed. Each |
12 |
match result needs to be closed individually though. |
13 |
|
14 |
This required some hoops to make it work with Packages file or binpkg |
15 |
repos. The latter are largely simulated now, and do not really benefit |
16 |
from the cheaper point and lookup approach that tree_match_atom tries to |
17 |
provide. |
18 |
|
19 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
20 |
|
21 |
libq/tree.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
22 |
libq/tree.h | 21 ++++++- |
23 |
2 files changed, 177 insertions(+), 25 deletions(-) |
24 |
|
25 |
diff --git a/libq/tree.c b/libq/tree.c |
26 |
index 4b9109e..d313f3b 100644 |
27 |
--- a/libq/tree.c |
28 |
+++ b/libq/tree.c |
29 |
@@ -388,14 +388,11 @@ tree_filter_pkg(const struct dirent *de) |
30 |
tree_pkg_ctx * |
31 |
tree_open_pkg(tree_cat_ctx *cat_ctx, const char *name) |
32 |
{ |
33 |
- tree_pkg_ctx *pkg_ctx = xmalloc(sizeof(*pkg_ctx)); |
34 |
+ tree_pkg_ctx *pkg_ctx = xzalloc(sizeof(*pkg_ctx)); |
35 |
pkg_ctx->name = name; |
36 |
- pkg_ctx->slot = NULL; |
37 |
pkg_ctx->repo = cat_ctx->ctx->repo; |
38 |
pkg_ctx->fd = -1; |
39 |
pkg_ctx->cat_ctx = cat_ctx; |
40 |
- pkg_ctx->atom = NULL; |
41 |
- pkg_ctx->meta = NULL; |
42 |
|
43 |
/* see if this pkg matches the query, here we can finally check |
44 |
* version conditions like >=, etc. */ |
45 |
@@ -1405,12 +1402,14 @@ tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv) |
46 |
match_key(IUSE); |
47 |
match_key(KEYWORDS); |
48 |
match_key(LICENSE); |
49 |
- match_key2(MD5, _md5_); |
50 |
- match_key2(SHA1, _eclasses_); |
51 |
+ match_key(MD5); |
52 |
+ match_key(SHA1); |
53 |
match_key(RDEPEND); |
54 |
match_key(SLOT); |
55 |
match_key(USE); |
56 |
match_key(PDEPEND); |
57 |
+ match_key2(REPO, repository); |
58 |
+ match_key(SIZE); |
59 |
#undef match_key |
60 |
#undef match_key2 |
61 |
} |
62 |
@@ -1430,6 +1429,7 @@ tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv) |
63 |
/* ensure we don't free a garbage pointer */ |
64 |
ctx->repo = NULL; |
65 |
ctx->do_sort = false; |
66 |
+ ctx->pkgs[0] = '\0'; |
67 |
|
68 |
return ret; |
69 |
} |
70 |
@@ -1580,34 +1580,167 @@ tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms) |
71 |
return state.cpf; |
72 |
} |
73 |
|
74 |
-tree_pkg_ctx * |
75 |
-tree_match_atom(tree_ctx *ctx, depend_atom *a) |
76 |
+struct tree_match_pkgs_cb_ctx { |
77 |
+ int flags; |
78 |
+ tree_match_ctx *ret; |
79 |
+}; |
80 |
+ |
81 |
+static int |
82 |
+tree_match_atom_packages_cb(tree_pkg_ctx *ctx, void *priv) |
83 |
+{ |
84 |
+ struct tree_match_pkgs_cb_ctx *rctx = priv; |
85 |
+ depend_atom *a; |
86 |
+ tree_match_ctx *n; |
87 |
+ |
88 |
+ /* skip anything after finding first match */ |
89 |
+ if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL) |
90 |
+ return 1; |
91 |
+ |
92 |
+ a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM); |
93 |
+ |
94 |
+ /* skip virtual category if not requested */ |
95 |
+ if (!(rctx->flags & TREE_MATCH_VIRTUAL) && |
96 |
+ strcmp(a->CATEGORY, "virtual") == 0) |
97 |
+ return 1; |
98 |
+ |
99 |
+ n = xzalloc(sizeof(tree_match_ctx)); |
100 |
+ n->free_atom = true; |
101 |
+ n->atom = atom_clone(a); |
102 |
+ if (rctx->flags & TREE_MATCH_METADATA) { |
103 |
+ n->meta = xmalloc(sizeof(*n->meta)); |
104 |
+ /* for Packages, all pointers to meta here are to the in memory |
105 |
+ * copy of the Packages file, so these pointers can just be |
106 |
+ * copied since the tree has to remain open, thus the pointers |
107 |
+ * will stay valid */ |
108 |
+ memcpy(n->meta, ctx->cat_ctx->ctx->pkgs, sizeof(*n->meta)); |
109 |
+ } |
110 |
+ |
111 |
+ n->next = rctx->ret; |
112 |
+ rctx->ret = n; |
113 |
+ |
114 |
+ return 0; |
115 |
+} |
116 |
+ |
117 |
+static int |
118 |
+tree_match_atom_binpkg_cb(tree_pkg_ctx *ctx, void *priv) |
119 |
+{ |
120 |
+ struct tree_match_pkgs_cb_ctx *rctx = priv; |
121 |
+ depend_atom *a; |
122 |
+ tree_match_ctx *n; |
123 |
+ |
124 |
+ /* skip anything after finding first match */ |
125 |
+ if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL) |
126 |
+ return 1; |
127 |
+ |
128 |
+ a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM); |
129 |
+ |
130 |
+ /* skip virtual category if not requested */ |
131 |
+ if (!(rctx->flags & TREE_MATCH_VIRTUAL) && |
132 |
+ strcmp(a->CATEGORY, "virtual") == 0) |
133 |
+ return 1; |
134 |
+ |
135 |
+ n = xzalloc(sizeof(tree_match_ctx)); |
136 |
+ n->free_atom = true; |
137 |
+ n->atom = atom_clone(a); |
138 |
+ if (rctx->flags & TREE_MATCH_METADATA) |
139 |
+ n->meta = tree_pkg_read(ctx); |
140 |
+ |
141 |
+ n->next = rctx->ret; |
142 |
+ rctx->ret = n; |
143 |
+ |
144 |
+ return 0; |
145 |
+} |
146 |
+ |
147 |
+tree_match_ctx * |
148 |
+tree_match_atom(tree_ctx *ctx, depend_atom *query, int flags) |
149 |
{ |
150 |
tree_cat_ctx *cat_ctx; |
151 |
tree_pkg_ctx *pkg_ctx; |
152 |
+ tree_match_ctx *ret = NULL; |
153 |
depend_atom *atom; |
154 |
|
155 |
+ if (ctx->cachetype == CACHE_PACKAGES) { |
156 |
+ struct tree_match_pkgs_cb_ctx rctx; |
157 |
+ /* Packages needs to be serviced separately because it doesn't |
158 |
+ * use a tree internally, but reads off of the Packages file */ |
159 |
+ rctx.flags = flags; |
160 |
+ rctx.ret = NULL; |
161 |
+ ctx->query_atom = query; |
162 |
+ tree_foreach_packages(ctx, tree_match_atom_packages_cb, &rctx); |
163 |
+ ctx->query_atom = NULL; |
164 |
+ return rctx.ret; |
165 |
+ } else if (ctx->cachetype == CACHE_BINPKGS) { |
166 |
+ struct tree_match_pkgs_cb_ctx rctx; |
167 |
+ /* this sulks, but binpkgs modify the pkg_ctx->name to strip off |
168 |
+ * .tbz2, and that makes it non-reusable */ |
169 |
+ rctx.flags = flags; |
170 |
+ rctx.ret = NULL; |
171 |
+ tree_foreach_pkg(ctx, tree_match_atom_binpkg_cb, &rctx, true, query); |
172 |
+ return rctx.ret; |
173 |
+ } |
174 |
+ |
175 |
+ /* activate cache for future lookups, tree_match_atom relies on |
176 |
+ * cache behaviour from tree, which means all categories and |
177 |
+ * packages remain in memory until tree_close is being called */ |
178 |
if (ctx->cache.categories == NULL) |
179 |
ctx->cache.categories = create_set(); |
180 |
|
181 |
- if (a->P == NULL) { |
182 |
- return NULL; |
183 |
- } else if (a->CATEGORY == NULL) { |
184 |
- /* loop through all cats and recurse */ |
185 |
- /* TODO: some day */ |
186 |
- return NULL; |
187 |
+ ctx->do_sort = true; /* sort uses buffer, which cache relies on */ |
188 |
+ ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */ |
189 |
+ |
190 |
+#define search_cat(C) \ |
191 |
+{ \ |
192 |
+ while ((pkg_ctx = tree_next_pkg(C)) != NULL) { \ |
193 |
+ atom = tree_get_atom(pkg_ctx, \ |
194 |
+ query->SLOT != NULL || flags & TREE_MATCH_FULL_ATOM); \ |
195 |
+fprintf(stderr, "fbg: %s\n", atom_to_string(atom)); \ |
196 |
+ if (flags & TREE_MATCH_VIRTUAL || \ |
197 |
+ strcmp(atom->CATEGORY, "virtual") != 0) \ |
198 |
+ if (atom_compare(atom, query) == EQUAL) { \ |
199 |
+ tree_match_ctx *n; \ |
200 |
+ n = xzalloc(sizeof(tree_match_ctx)); \ |
201 |
+ n->free_atom = false; \ |
202 |
+ n->atom = atom; \ |
203 |
+ if (flags & TREE_MATCH_METADATA) \ |
204 |
+ n->meta = tree_pkg_read(pkg_ctx); \ |
205 |
+ n->next = ret; \ |
206 |
+ ret = n; \ |
207 |
+ } \ |
208 |
+ if (flags & TREE_MATCH_FIRST && ret != NULL) \ |
209 |
+ break; \ |
210 |
+ } \ |
211 |
+ C->pkg_cur = 0; /* reset to allow another traversal */ \ |
212 |
+} |
213 |
+ |
214 |
+ if (query->CATEGORY == NULL) { |
215 |
+ /* loop through all cats */ |
216 |
+ while ((cat_ctx = tree_next_cat(ctx)) != NULL) { |
217 |
+ search_cat(cat_ctx); |
218 |
+ if (ret != NULL && flags & TREE_MATCH_FIRST) |
219 |
+ break; |
220 |
+ } |
221 |
+ /* allow running again through the cats */ |
222 |
+ ctx->cat_cur = 0; |
223 |
} else { |
224 |
/* try CAT, and PN for latest version */ |
225 |
- if ((cat_ctx = tree_open_cat(ctx, a->CATEGORY)) == NULL) |
226 |
- return NULL; |
227 |
- ctx->do_sort = true; /* sort uses buffer, which cache relies on */ |
228 |
- ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */ |
229 |
- while ((pkg_ctx = tree_next_pkg(cat_ctx)) != NULL) { |
230 |
- atom = tree_get_atom(pkg_ctx, a->SLOT != NULL); |
231 |
- if (atom_compare(atom, a) == EQUAL) |
232 |
- return pkg_ctx; |
233 |
- } |
234 |
+ if ((cat_ctx = tree_open_cat(ctx, query->CATEGORY)) != NULL) |
235 |
+ search_cat(cat_ctx); |
236 |
+ } |
237 |
|
238 |
- return NULL; |
239 |
+ return ret; |
240 |
+} |
241 |
+ |
242 |
+void |
243 |
+tree_match_close(tree_match_ctx *match) |
244 |
+{ |
245 |
+ tree_match_ctx *w; |
246 |
+ |
247 |
+ for (w = NULL; match != NULL; match = w) { |
248 |
+ w = match->next; |
249 |
+ if (match->free_atom) |
250 |
+ atom_implode(match->atom); |
251 |
+ if (match->meta != NULL) |
252 |
+ free(match->meta); |
253 |
+ free(match); |
254 |
} |
255 |
} |
256 |
|
257 |
diff --git a/libq/tree.h b/libq/tree.h |
258 |
index eaee7ad..900b998 100644 |
259 |
--- a/libq/tree.h |
260 |
+++ b/libq/tree.h |
261 |
@@ -18,6 +18,7 @@ typedef struct tree_cat_ctx tree_cat_ctx; |
262 |
typedef struct tree_pkg_ctx tree_pkg_ctx; |
263 |
typedef struct tree_pkg_meta tree_pkg_meta; |
264 |
typedef struct tree_metadata_xml tree_metadata_xml; |
265 |
+typedef struct tree_match_ctx tree_match_ctx; |
266 |
|
267 |
/* tree context */ |
268 |
struct tree_ctx { |
269 |
@@ -100,6 +101,9 @@ struct tree_pkg_meta { |
270 |
char *Q_USE; |
271 |
char *Q_EPREFIX; |
272 |
char *Q_repository; |
273 |
+ char *Q_MD5; |
274 |
+ char *Q_SHA1; |
275 |
+#define Q_SIZE Q_SRC_URI |
276 |
/* These are MD5-Cache only */ |
277 |
char *Q__eclasses_; |
278 |
char *Q__md5_; |
279 |
@@ -113,6 +117,15 @@ struct tree_metadata_xml { |
280 |
} *email; |
281 |
}; |
282 |
|
283 |
+/* used with tree_match_atom, both atom and meta are fully materialised |
284 |
+ * (populated and deep copied) when set */ |
285 |
+struct tree_match_ctx { |
286 |
+ depend_atom *atom; |
287 |
+ tree_pkg_meta *meta; |
288 |
+ tree_match_ctx *next; |
289 |
+ int free_atom; |
290 |
+}; |
291 |
+ |
292 |
/* foreach pkg callback function signature */ |
293 |
typedef int (tree_pkg_cb)(tree_pkg_ctx *, void *priv); |
294 |
|
295 |
@@ -138,6 +151,12 @@ int tree_foreach_pkg(tree_ctx *ctx, tree_pkg_cb callback, void *priv, |
296 |
tree_foreach_pkg(ctx, cb, priv, true, query); |
297 |
set *tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms); |
298 |
depend_atom *tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete); |
299 |
-tree_pkg_ctx *tree_match_atom(tree_ctx *t, depend_atom *a); |
300 |
+tree_match_ctx *tree_match_atom(tree_ctx *t, depend_atom *q, int flags); |
301 |
+#define TREE_MATCH_FULL_ATOM 1<<1 |
302 |
+#define TREE_MATCH_METADATA 1<<2 |
303 |
+#define TREE_MATCH_FIRST 1<<3 |
304 |
+#define TREE_MATCH_VIRTUAL 1<<4 |
305 |
+#define TREE_MATCH_DEFAULT TREE_MATCH_VIRTUAL |
306 |
+void tree_match_close(tree_match_ctx *t); |
307 |
|
308 |
#endif |