xref: /freebsd/contrib/pkgconf/libpkgconf/queue.c (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery  * queue.c
3*a3cefe7fSPierre Pronchery  * compilation of a list of packages into a world dependency set
4*a3cefe7fSPierre Pronchery  *
5*a3cefe7fSPierre Pronchery  * Copyright (c) 2012 pkgconf authors (see AUTHORS).
6*a3cefe7fSPierre Pronchery  *
7*a3cefe7fSPierre Pronchery  * Permission to use, copy, modify, and/or distribute this software for any
8*a3cefe7fSPierre Pronchery  * purpose with or without fee is hereby granted, provided that the above
9*a3cefe7fSPierre Pronchery  * copyright notice and this permission notice appear in all copies.
10*a3cefe7fSPierre Pronchery  *
11*a3cefe7fSPierre Pronchery  * This software is provided 'as is' and without any warranty, express or
12*a3cefe7fSPierre Pronchery  * implied.  In no event shall the authors be liable for any damages arising
13*a3cefe7fSPierre Pronchery  * from the use of this software.
14*a3cefe7fSPierre Pronchery  */
15*a3cefe7fSPierre Pronchery 
16*a3cefe7fSPierre Pronchery #include <libpkgconf/stdinc.h>
17*a3cefe7fSPierre Pronchery #include <libpkgconf/libpkgconf.h>
18*a3cefe7fSPierre Pronchery 
19*a3cefe7fSPierre Pronchery /*
20*a3cefe7fSPierre Pronchery  * !doc
21*a3cefe7fSPierre Pronchery  *
22*a3cefe7fSPierre Pronchery  * libpkgconf `queue` module
23*a3cefe7fSPierre Pronchery  * =========================
24*a3cefe7fSPierre Pronchery  *
25*a3cefe7fSPierre Pronchery  * The `queue` module provides an interface that allows easily building a dependency graph from an
26*a3cefe7fSPierre Pronchery  * arbitrary set of dependencies.  It also provides support for doing "preflight" checks on the entire
27*a3cefe7fSPierre Pronchery  * dependency graph prior to working with it.
28*a3cefe7fSPierre Pronchery  *
29*a3cefe7fSPierre Pronchery  * Using the `queue` module functions is the recommended way of working with dependency graphs.
30*a3cefe7fSPierre Pronchery  */
31*a3cefe7fSPierre Pronchery 
32*a3cefe7fSPierre Pronchery /*
33*a3cefe7fSPierre Pronchery  * !doc
34*a3cefe7fSPierre Pronchery  *
35*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_queue_push(pkgconf_list_t *list, const char *package)
36*a3cefe7fSPierre Pronchery  *
37*a3cefe7fSPierre Pronchery  *    Pushes a requested dependency onto the dependency resolver's queue.
38*a3cefe7fSPierre Pronchery  *
39*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: the dependency resolution queue to add the package request to.
40*a3cefe7fSPierre Pronchery  *    :param char* package: the dependency atom requested
41*a3cefe7fSPierre Pronchery  *    :return: nothing
42*a3cefe7fSPierre Pronchery  */
43*a3cefe7fSPierre Pronchery void
pkgconf_queue_push(pkgconf_list_t * list,const char * package)44*a3cefe7fSPierre Pronchery pkgconf_queue_push(pkgconf_list_t *list, const char *package)
45*a3cefe7fSPierre Pronchery {
46*a3cefe7fSPierre Pronchery 	pkgconf_queue_t *pkgq = calloc(1, sizeof(pkgconf_queue_t));
47*a3cefe7fSPierre Pronchery 
48*a3cefe7fSPierre Pronchery 	pkgq->package = strdup(package);
49*a3cefe7fSPierre Pronchery 	pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
50*a3cefe7fSPierre Pronchery }
51*a3cefe7fSPierre Pronchery 
52*a3cefe7fSPierre Pronchery /*
53*a3cefe7fSPierre Pronchery  * !doc
54*a3cefe7fSPierre Pronchery  *
55*a3cefe7fSPierre Pronchery  * .. c:function:: bool pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list)
56*a3cefe7fSPierre Pronchery  *
57*a3cefe7fSPierre Pronchery  *    Compile a dependency resolution queue into a dependency resolution problem if possible, otherwise report an error.
58*a3cefe7fSPierre Pronchery  *
59*a3cefe7fSPierre Pronchery  *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
60*a3cefe7fSPierre Pronchery  *    :param pkgconf_pkg_t* world: The designated root of the dependency graph.
61*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: The list of dependency requests to consider.
62*a3cefe7fSPierre Pronchery  *    :return: true if the built dependency resolution problem is consistent, else false
63*a3cefe7fSPierre Pronchery  *    :rtype: bool
64*a3cefe7fSPierre Pronchery  */
65*a3cefe7fSPierre Pronchery bool
pkgconf_queue_compile(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * list)66*a3cefe7fSPierre Pronchery pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list)
67*a3cefe7fSPierre Pronchery {
68*a3cefe7fSPierre Pronchery 	pkgconf_node_t *iter;
69*a3cefe7fSPierre Pronchery 
70*a3cefe7fSPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
71*a3cefe7fSPierre Pronchery 	{
72*a3cefe7fSPierre Pronchery 		pkgconf_queue_t *pkgq;
73*a3cefe7fSPierre Pronchery 
74*a3cefe7fSPierre Pronchery 		pkgq = iter->data;
75*a3cefe7fSPierre Pronchery 		pkgconf_dependency_parse(client, world, &world->required, pkgq->package, PKGCONF_PKG_DEPF_QUERY);
76*a3cefe7fSPierre Pronchery 	}
77*a3cefe7fSPierre Pronchery 
78*a3cefe7fSPierre Pronchery 	return (world->required.head != NULL);
79*a3cefe7fSPierre Pronchery }
80*a3cefe7fSPierre Pronchery 
81*a3cefe7fSPierre Pronchery /*
82*a3cefe7fSPierre Pronchery  * !doc
83*a3cefe7fSPierre Pronchery  *
84*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_queue_free(pkgconf_list_t *list)
85*a3cefe7fSPierre Pronchery  *
86*a3cefe7fSPierre Pronchery  *    Release any memory related to a dependency resolution queue.
87*a3cefe7fSPierre Pronchery  *
88*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: The dependency resolution queue to release.
89*a3cefe7fSPierre Pronchery  *    :return: nothing
90*a3cefe7fSPierre Pronchery  */
91*a3cefe7fSPierre Pronchery void
pkgconf_queue_free(pkgconf_list_t * list)92*a3cefe7fSPierre Pronchery pkgconf_queue_free(pkgconf_list_t *list)
93*a3cefe7fSPierre Pronchery {
94*a3cefe7fSPierre Pronchery 	pkgconf_node_t *node, *tnode;
95*a3cefe7fSPierre Pronchery 
96*a3cefe7fSPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, tnode, node)
97*a3cefe7fSPierre Pronchery 	{
98*a3cefe7fSPierre Pronchery 		pkgconf_queue_t *pkgq = node->data;
99*a3cefe7fSPierre Pronchery 
100*a3cefe7fSPierre Pronchery 		free(pkgq->package);
101*a3cefe7fSPierre Pronchery 		free(pkgq);
102*a3cefe7fSPierre Pronchery 	}
103*a3cefe7fSPierre Pronchery }
104*a3cefe7fSPierre Pronchery 
105*a3cefe7fSPierre Pronchery static void
pkgconf_queue_mark_public(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)106*a3cefe7fSPierre Pronchery pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
107*a3cefe7fSPierre Pronchery {
108*a3cefe7fSPierre Pronchery 	if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
109*a3cefe7fSPierre Pronchery 	{
110*a3cefe7fSPierre Pronchery 		pkgconf_list_t *list = data;
111*a3cefe7fSPierre Pronchery 		pkgconf_node_t *node;
112*a3cefe7fSPierre Pronchery 
113*a3cefe7fSPierre Pronchery 		PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
114*a3cefe7fSPierre Pronchery 		{
115*a3cefe7fSPierre Pronchery 			pkgconf_dependency_t *dep = node->data;
116*a3cefe7fSPierre Pronchery 			if (dep->match == pkg)
117*a3cefe7fSPierre Pronchery 				dep->flags &= ~PKGCONF_PKG_DEPF_PRIVATE;
118*a3cefe7fSPierre Pronchery 		}
119*a3cefe7fSPierre Pronchery 
120*a3cefe7fSPierre Pronchery 		pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
121*a3cefe7fSPierre Pronchery 
122*a3cefe7fSPierre Pronchery 		PKGCONF_TRACE(client, "%s: updated, public", pkg->id);
123*a3cefe7fSPierre Pronchery 	}
124*a3cefe7fSPierre Pronchery }
125*a3cefe7fSPierre Pronchery 
126*a3cefe7fSPierre Pronchery static unsigned int
127*a3cefe7fSPierre Pronchery pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
128*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t *root,
129*a3cefe7fSPierre Pronchery 	void *data,
130*a3cefe7fSPierre Pronchery 	int maxdepth);
131*a3cefe7fSPierre Pronchery 
132*a3cefe7fSPierre Pronchery static inline unsigned int
pkgconf_queue_collect_dependencies_walk(pkgconf_client_t * client,pkgconf_list_t * deplist,void * data,int depth)133*a3cefe7fSPierre Pronchery pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
134*a3cefe7fSPierre Pronchery 	pkgconf_list_t *deplist,
135*a3cefe7fSPierre Pronchery 	void *data,
136*a3cefe7fSPierre Pronchery 	int depth)
137*a3cefe7fSPierre Pronchery {
138*a3cefe7fSPierre Pronchery 	unsigned int eflags = PKGCONF_PKG_ERRF_OK;
139*a3cefe7fSPierre Pronchery 	pkgconf_node_t *node;
140*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t *world = data;
141*a3cefe7fSPierre Pronchery 
142*a3cefe7fSPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_REVERSE(deplist->tail, node)
143*a3cefe7fSPierre Pronchery 	{
144*a3cefe7fSPierre Pronchery 		pkgconf_dependency_t *dep = node->data;
145*a3cefe7fSPierre Pronchery 		pkgconf_dependency_t *flattened_dep;
146*a3cefe7fSPierre Pronchery 		pkgconf_pkg_t *pkg = dep->match;
147*a3cefe7fSPierre Pronchery 
148*a3cefe7fSPierre Pronchery 		if (*dep->package == '\0')
149*a3cefe7fSPierre Pronchery 			continue;
150*a3cefe7fSPierre Pronchery 
151*a3cefe7fSPierre Pronchery 		if (pkg == NULL)
152*a3cefe7fSPierre Pronchery 		{
153*a3cefe7fSPierre Pronchery 			PKGCONF_TRACE(client, "WTF: unmatched dependency %p <%s>", dep, dep->package);
154*a3cefe7fSPierre Pronchery 			continue;
155*a3cefe7fSPierre Pronchery 		}
156*a3cefe7fSPierre Pronchery 
157*a3cefe7fSPierre Pronchery 		if (pkg->serial == client->serial)
158*a3cefe7fSPierre Pronchery 			continue;
159*a3cefe7fSPierre Pronchery 
160*a3cefe7fSPierre Pronchery 		if (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE)
161*a3cefe7fSPierre Pronchery 			pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE;
162*a3cefe7fSPierre Pronchery 		else
163*a3cefe7fSPierre Pronchery 			pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
164*a3cefe7fSPierre Pronchery 
165*a3cefe7fSPierre Pronchery 		eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1);
166*a3cefe7fSPierre Pronchery 
167*a3cefe7fSPierre Pronchery 		flattened_dep = pkgconf_dependency_copy(client, dep);
168*a3cefe7fSPierre Pronchery 		pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
169*a3cefe7fSPierre Pronchery 	}
170*a3cefe7fSPierre Pronchery 
171*a3cefe7fSPierre Pronchery 	return eflags;
172*a3cefe7fSPierre Pronchery }
173*a3cefe7fSPierre Pronchery 
174*a3cefe7fSPierre Pronchery static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t * client,pkgconf_pkg_t * root,void * data,int maxdepth)175*a3cefe7fSPierre Pronchery pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
176*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t *root,
177*a3cefe7fSPierre Pronchery 	void *data,
178*a3cefe7fSPierre Pronchery 	int maxdepth)
179*a3cefe7fSPierre Pronchery {
180*a3cefe7fSPierre Pronchery 	unsigned int eflags = PKGCONF_PKG_ERRF_OK;
181*a3cefe7fSPierre Pronchery 
182*a3cefe7fSPierre Pronchery 	if (maxdepth == 0)
183*a3cefe7fSPierre Pronchery 		return eflags;
184*a3cefe7fSPierre Pronchery 
185*a3cefe7fSPierre Pronchery 	/* Short-circuit if we have already visited this node.
186*a3cefe7fSPierre Pronchery 	 */
187*a3cefe7fSPierre Pronchery 	if (root->serial == client->serial)
188*a3cefe7fSPierre Pronchery 		return eflags;
189*a3cefe7fSPierre Pronchery 
190*a3cefe7fSPierre Pronchery 	root->serial = client->serial;
191*a3cefe7fSPierre Pronchery 
192*a3cefe7fSPierre Pronchery 	PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth);
193*a3cefe7fSPierre Pronchery 
194*a3cefe7fSPierre Pronchery 	/* XXX: ugly */
195*a3cefe7fSPierre Pronchery 	const unsigned int saved_flags = client->flags;
196*a3cefe7fSPierre Pronchery 	client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
197*a3cefe7fSPierre Pronchery 	eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth);
198*a3cefe7fSPierre Pronchery 	client->flags = saved_flags;
199*a3cefe7fSPierre Pronchery 	if (eflags != PKGCONF_PKG_ERRF_OK)
200*a3cefe7fSPierre Pronchery 		return eflags;
201*a3cefe7fSPierre Pronchery 
202*a3cefe7fSPierre Pronchery 	PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth);
203*a3cefe7fSPierre Pronchery 
204*a3cefe7fSPierre Pronchery 	eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth);
205*a3cefe7fSPierre Pronchery 	if (eflags != PKGCONF_PKG_ERRF_OK)
206*a3cefe7fSPierre Pronchery 		return eflags;
207*a3cefe7fSPierre Pronchery 
208*a3cefe7fSPierre Pronchery 	PKGCONF_TRACE(client, "%s: finished, %s", root->id, (root->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) ? "private" : "public");
209*a3cefe7fSPierre Pronchery 
210*a3cefe7fSPierre Pronchery 	return eflags;
211*a3cefe7fSPierre Pronchery }
212*a3cefe7fSPierre Pronchery 
213*a3cefe7fSPierre Pronchery static inline unsigned int
pkgconf_queue_collect_dependencies(pkgconf_client_t * client,pkgconf_pkg_t * root,void * data,int maxdepth)214*a3cefe7fSPierre Pronchery pkgconf_queue_collect_dependencies(pkgconf_client_t *client,
215*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t *root,
216*a3cefe7fSPierre Pronchery 	void *data,
217*a3cefe7fSPierre Pronchery 	int maxdepth)
218*a3cefe7fSPierre Pronchery {
219*a3cefe7fSPierre Pronchery 	++client->serial;
220*a3cefe7fSPierre Pronchery 	return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth);
221*a3cefe7fSPierre Pronchery }
222*a3cefe7fSPierre Pronchery 
223*a3cefe7fSPierre Pronchery static inline unsigned int
pkgconf_queue_verify(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * list,int maxdepth)224*a3cefe7fSPierre Pronchery pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth)
225*a3cefe7fSPierre Pronchery {
226*a3cefe7fSPierre Pronchery 	unsigned int result;
227*a3cefe7fSPierre Pronchery 	const unsigned int saved_flags = client->flags;
228*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t initial_world = {
229*a3cefe7fSPierre Pronchery 		.id = "user:request",
230*a3cefe7fSPierre Pronchery 		.realname = "virtual world package",
231*a3cefe7fSPierre Pronchery 		.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
232*a3cefe7fSPierre Pronchery 	};
233*a3cefe7fSPierre Pronchery 
234*a3cefe7fSPierre Pronchery 	if (!pkgconf_queue_compile(client, &initial_world, list))
235*a3cefe7fSPierre Pronchery 	{
236*a3cefe7fSPierre Pronchery 		pkgconf_solution_free(client, &initial_world);
237*a3cefe7fSPierre Pronchery 		return PKGCONF_PKG_ERRF_DEPGRAPH_BREAK;
238*a3cefe7fSPierre Pronchery 	}
239*a3cefe7fSPierre Pronchery 
240*a3cefe7fSPierre Pronchery 	PKGCONF_TRACE(client, "solving");
241*a3cefe7fSPierre Pronchery 	result = pkgconf_pkg_traverse(client, &initial_world, NULL, NULL, maxdepth, 0);
242*a3cefe7fSPierre Pronchery 	if (result != PKGCONF_PKG_ERRF_OK)
243*a3cefe7fSPierre Pronchery 	{
244*a3cefe7fSPierre Pronchery 		pkgconf_solution_free(client, &initial_world);
245*a3cefe7fSPierre Pronchery 		return result;
246*a3cefe7fSPierre Pronchery 	}
247*a3cefe7fSPierre Pronchery 
248*a3cefe7fSPierre Pronchery 	PKGCONF_TRACE(client, "flattening");
249*a3cefe7fSPierre Pronchery 	result = pkgconf_queue_collect_dependencies(client, &initial_world, world, maxdepth);
250*a3cefe7fSPierre Pronchery 	if (result != PKGCONF_PKG_ERRF_OK)
251*a3cefe7fSPierre Pronchery 	{
252*a3cefe7fSPierre Pronchery 		pkgconf_solution_free(client, &initial_world);
253*a3cefe7fSPierre Pronchery 		return result;
254*a3cefe7fSPierre Pronchery 	}
255*a3cefe7fSPierre Pronchery 
256*a3cefe7fSPierre Pronchery 	if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
257*a3cefe7fSPierre Pronchery 	{
258*a3cefe7fSPierre Pronchery 		PKGCONF_TRACE(client, "marking public deps");
259*a3cefe7fSPierre Pronchery 		client->flags &= ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
260*a3cefe7fSPierre Pronchery 		client->flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
261*a3cefe7fSPierre Pronchery 		result = pkgconf_pkg_traverse(client, &initial_world, pkgconf_queue_mark_public, &world->required, maxdepth, 0);
262*a3cefe7fSPierre Pronchery 		client->flags = saved_flags;
263*a3cefe7fSPierre Pronchery 		if (result != PKGCONF_PKG_ERRF_OK)
264*a3cefe7fSPierre Pronchery 		{
265*a3cefe7fSPierre Pronchery 			pkgconf_solution_free(client, &initial_world);
266*a3cefe7fSPierre Pronchery 			return result;
267*a3cefe7fSPierre Pronchery 		}
268*a3cefe7fSPierre Pronchery 	}
269*a3cefe7fSPierre Pronchery 
270*a3cefe7fSPierre Pronchery 	/* free the initial solution */
271*a3cefe7fSPierre Pronchery 	pkgconf_solution_free(client, &initial_world);
272*a3cefe7fSPierre Pronchery 
273*a3cefe7fSPierre Pronchery 	return PKGCONF_PKG_ERRF_OK;
274*a3cefe7fSPierre Pronchery }
275*a3cefe7fSPierre Pronchery 
276*a3cefe7fSPierre Pronchery /*
277*a3cefe7fSPierre Pronchery  * !doc
278*a3cefe7fSPierre Pronchery  *
279*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world, int maxdepth)
280*a3cefe7fSPierre Pronchery  *
281*a3cefe7fSPierre Pronchery  *    Removes references to package nodes contained in a solution.
282*a3cefe7fSPierre Pronchery  *
283*a3cefe7fSPierre Pronchery  *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
284*a3cefe7fSPierre Pronchery  *    :param pkgconf_pkg_t* world: The root for the generated dependency graph.  Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
285*a3cefe7fSPierre Pronchery  *    :returns: nothing
286*a3cefe7fSPierre Pronchery  */
287*a3cefe7fSPierre Pronchery void
pkgconf_solution_free(pkgconf_client_t * client,pkgconf_pkg_t * world)288*a3cefe7fSPierre Pronchery pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world)
289*a3cefe7fSPierre Pronchery {
290*a3cefe7fSPierre Pronchery 	(void) client;
291*a3cefe7fSPierre Pronchery 
292*a3cefe7fSPierre Pronchery 	if (world->flags & PKGCONF_PKG_PROPF_VIRTUAL)
293*a3cefe7fSPierre Pronchery 	{
294*a3cefe7fSPierre Pronchery 		pkgconf_dependency_free(&world->required);
295*a3cefe7fSPierre Pronchery 		pkgconf_dependency_free(&world->requires_private);
296*a3cefe7fSPierre Pronchery 	}
297*a3cefe7fSPierre Pronchery }
298*a3cefe7fSPierre Pronchery 
299*a3cefe7fSPierre Pronchery /*
300*a3cefe7fSPierre Pronchery  * !doc
301*a3cefe7fSPierre Pronchery  *
302*a3cefe7fSPierre Pronchery  * .. c:function:: bool pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth)
303*a3cefe7fSPierre Pronchery  *
304*a3cefe7fSPierre Pronchery  *    Solves and flattens the dependency graph for the supplied dependency list.
305*a3cefe7fSPierre Pronchery  *
306*a3cefe7fSPierre Pronchery  *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
307*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: The list of dependency requests to consider.
308*a3cefe7fSPierre Pronchery  *    :param pkgconf_pkg_t* world: The root for the generated dependency graph, provided by the caller.  Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
309*a3cefe7fSPierre Pronchery  *    :param int maxdepth: The maximum allowed depth for the dependency resolver.  A depth of -1 means unlimited.
310*a3cefe7fSPierre Pronchery  *    :returns: true if the dependency resolver found a solution, otherwise false.
311*a3cefe7fSPierre Pronchery  *    :rtype: bool
312*a3cefe7fSPierre Pronchery  */
313*a3cefe7fSPierre Pronchery bool
pkgconf_queue_solve(pkgconf_client_t * client,pkgconf_list_t * list,pkgconf_pkg_t * world,int maxdepth)314*a3cefe7fSPierre Pronchery pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth)
315*a3cefe7fSPierre Pronchery {
316*a3cefe7fSPierre Pronchery 	/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
317*a3cefe7fSPierre Pronchery 	if (!maxdepth)
318*a3cefe7fSPierre Pronchery 		maxdepth = -1;
319*a3cefe7fSPierre Pronchery 
320*a3cefe7fSPierre Pronchery 	unsigned int flags = client->flags;
321*a3cefe7fSPierre Pronchery 	client->flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
322*a3cefe7fSPierre Pronchery 
323*a3cefe7fSPierre Pronchery 	unsigned int ret = pkgconf_queue_verify(client, world, list, maxdepth);
324*a3cefe7fSPierre Pronchery 	client->flags = flags;
325*a3cefe7fSPierre Pronchery 
326*a3cefe7fSPierre Pronchery 	return ret == PKGCONF_PKG_ERRF_OK;
327*a3cefe7fSPierre Pronchery }
328*a3cefe7fSPierre Pronchery 
329*a3cefe7fSPierre Pronchery /*
330*a3cefe7fSPierre Pronchery  * !doc
331*a3cefe7fSPierre Pronchery  *
332*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
333*a3cefe7fSPierre Pronchery  *
334*a3cefe7fSPierre Pronchery  *    Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem and
335*a3cefe7fSPierre Pronchery  *    feed the solution to a callback function if a complete dependency graph is found.
336*a3cefe7fSPierre Pronchery  *
337*a3cefe7fSPierre Pronchery  *    This function should not be used in new code.  Use pkgconf_queue_solve instead.
338*a3cefe7fSPierre Pronchery  *
339*a3cefe7fSPierre Pronchery  *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
340*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: The list of dependency requests to consider.
341*a3cefe7fSPierre Pronchery  *    :param pkgconf_queue_apply_func_t func: The callback function to call if a solution is found by the dependency resolver.
342*a3cefe7fSPierre Pronchery  *    :param int maxdepth: The maximum allowed depth for the dependency resolver.  A depth of -1 means unlimited.
343*a3cefe7fSPierre Pronchery  *    :param void* data: An opaque pointer which is passed to the callback function.
344*a3cefe7fSPierre Pronchery  *    :returns: true if the dependency resolver found a solution, otherwise false.
345*a3cefe7fSPierre Pronchery  *    :rtype: bool
346*a3cefe7fSPierre Pronchery  */
347*a3cefe7fSPierre Pronchery bool
pkgconf_queue_apply(pkgconf_client_t * client,pkgconf_list_t * list,pkgconf_queue_apply_func_t func,int maxdepth,void * data)348*a3cefe7fSPierre Pronchery pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
349*a3cefe7fSPierre Pronchery {
350*a3cefe7fSPierre Pronchery 	bool ret = false;
351*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t world = {
352*a3cefe7fSPierre Pronchery 		.id = "virtual:world",
353*a3cefe7fSPierre Pronchery 		.realname = "virtual world package",
354*a3cefe7fSPierre Pronchery 		.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
355*a3cefe7fSPierre Pronchery 	};
356*a3cefe7fSPierre Pronchery 
357*a3cefe7fSPierre Pronchery 	/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
358*a3cefe7fSPierre Pronchery 	if (!maxdepth)
359*a3cefe7fSPierre Pronchery 		maxdepth = -1;
360*a3cefe7fSPierre Pronchery 
361*a3cefe7fSPierre Pronchery 	if (!pkgconf_queue_solve(client, list, &world, maxdepth))
362*a3cefe7fSPierre Pronchery 		goto cleanup;
363*a3cefe7fSPierre Pronchery 
364*a3cefe7fSPierre Pronchery 	/* the world dependency set is flattened after it is returned from pkgconf_queue_verify */
365*a3cefe7fSPierre Pronchery 	if (!func(client, &world, data, maxdepth))
366*a3cefe7fSPierre Pronchery 		goto cleanup;
367*a3cefe7fSPierre Pronchery 
368*a3cefe7fSPierre Pronchery 	ret = true;
369*a3cefe7fSPierre Pronchery 
370*a3cefe7fSPierre Pronchery cleanup:
371*a3cefe7fSPierre Pronchery 	pkgconf_pkg_free(client, &world);
372*a3cefe7fSPierre Pronchery 	return ret;
373*a3cefe7fSPierre Pronchery }
374*a3cefe7fSPierre Pronchery 
375*a3cefe7fSPierre Pronchery /*
376*a3cefe7fSPierre Pronchery  * !doc
377*a3cefe7fSPierre Pronchery  *
378*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
379*a3cefe7fSPierre Pronchery  *
380*a3cefe7fSPierre Pronchery  *    Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem.
381*a3cefe7fSPierre Pronchery  *
382*a3cefe7fSPierre Pronchery  *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
383*a3cefe7fSPierre Pronchery  *    :param pkgconf_list_t* list: The list of dependency requests to consider.
384*a3cefe7fSPierre Pronchery  *    :param int maxdepth: The maximum allowed depth for the dependency resolver.  A depth of -1 means unlimited.
385*a3cefe7fSPierre Pronchery  *    :returns: true if the dependency resolver found a solution, otherwise false.
386*a3cefe7fSPierre Pronchery  *    :rtype: bool
387*a3cefe7fSPierre Pronchery  */
388*a3cefe7fSPierre Pronchery bool
pkgconf_queue_validate(pkgconf_client_t * client,pkgconf_list_t * list,int maxdepth)389*a3cefe7fSPierre Pronchery pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, int maxdepth)
390*a3cefe7fSPierre Pronchery {
391*a3cefe7fSPierre Pronchery 	bool retval = true;
392*a3cefe7fSPierre Pronchery 	pkgconf_pkg_t world = {
393*a3cefe7fSPierre Pronchery 		.id = "virtual:world",
394*a3cefe7fSPierre Pronchery 		.realname = "virtual world package",
395*a3cefe7fSPierre Pronchery 		.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
396*a3cefe7fSPierre Pronchery 	};
397*a3cefe7fSPierre Pronchery 
398*a3cefe7fSPierre Pronchery 	/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
399*a3cefe7fSPierre Pronchery 	if (!maxdepth)
400*a3cefe7fSPierre Pronchery 		maxdepth = -1;
401*a3cefe7fSPierre Pronchery 
402*a3cefe7fSPierre Pronchery 	if (pkgconf_queue_verify(client, &world, list, maxdepth) != PKGCONF_PKG_ERRF_OK)
403*a3cefe7fSPierre Pronchery 		retval = false;
404*a3cefe7fSPierre Pronchery 
405*a3cefe7fSPierre Pronchery 	pkgconf_pkg_free(client, &world);
406*a3cefe7fSPierre Pronchery 
407*a3cefe7fSPierre Pronchery 	return retval;
408*a3cefe7fSPierre Pronchery }
409