XBPS Library API 20240111
The X Binary Package System
package_fulldeptree.c
1/*-
2 * Copyright (c) 2014-2020 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <stdio.h>
27#include <stdbool.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31
32#include "xbps_api_impl.h"
33#include "uthash.h"
34
35struct item;
36
37struct depn {
38 struct depn *dnext;
39 struct item *item;
40};
41
42struct item {
43 char *pkgn; /* hash key */
44 const char *pkgver;
45 xbps_array_t rdeps;
46 struct depn *dbase;
48};
49
50static struct item *items = NULL;
51static xbps_array_t result;
52
53static struct item *
54lookupItem(const char *pkgn)
55{
56 struct item *item = NULL;
57
58 assert(pkgn);
59
60 HASH_FIND_STR(items, pkgn, item);
61 return item;
62}
63
64static struct item *
65addItem(xbps_array_t rdeps, const char *pkgn, const char *pkgver)
66{
67 struct item *item = NULL;
68
69 assert(pkgn);
70 assert(pkgver);
71
72 HASH_FIND_STR(items, pkgn, item);
73 if (item)
74 return item;
75
76 item = malloc(sizeof(*item));
77 assert(item);
78 item->pkgn = strdup(pkgn);
79 item->pkgver = pkgver;
80 item->rdeps = rdeps;
81 item->dbase = NULL;
82 HASH_ADD_KEYPTR(hh, items, item->pkgn, strlen(pkgn), item);
83
84 return item;
85}
86
87static void
88addDepn(struct item *item, struct item *xitem)
89{
90 struct depn *depn = calloc(1, sizeof(*depn));
91
92 assert(depn);
93 assert(item);
94 assert(xitem);
95
96 depn->item = item;
97 depn->dnext = xitem->dbase;
98 xitem->dbase = depn;
99}
100
101static void
102add_deps_recursive(struct item *item, bool first)
103{
104 struct depn *dep;
105 xbps_string_t str;
106
107 if (xbps_match_string_in_array(result, item->pkgver))
108 return;
109
110 for (dep = item->dbase; dep; dep = dep->dnext)
111 add_deps_recursive(dep->item, false);
112
113 if (first)
114 return;
115
116 str = xbps_string_create_cstring(item->pkgver);
117 assert(str);
118 xbps_array_add_first(result, str);
119 xbps_object_release(str);
120}
121
122static void
123cleanup(void)
124{
125 struct item *item, *itmp;
126
127 HASH_ITER(hh, items, item, itmp) {
128 HASH_DEL(items, item);
129 if (item->dbase)
130 free(item->dbase);
131 free(item->pkgn);
132 free(item);
133 }
134}
135
136/*
137 * Recursively calculate all dependencies.
138 */
139static struct item *
140ordered_depends(struct xbps_handle *xhp, xbps_dictionary_t pkgd, bool rpool,
141 size_t depth)
142{
143 xbps_array_t rdeps, provides;
144 xbps_string_t str;
145 struct item *item = NULL, *xitem = NULL;
146 const char *pkgver = NULL, *pkgname = NULL;
147
148 assert(xhp);
149 assert(pkgd);
150
151 rdeps = xbps_dictionary_get(pkgd, "run_depends");
152 provides = xbps_dictionary_get(pkgd, "provides");
153 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname);
154
155 item = lookupItem(pkgname);
156 if (item) {
157 add_deps_recursive(item, depth == 0);
158 return item;
159 }
160
161 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
162 abort();
163 }
164
165 item = addItem(rdeps, pkgname, pkgver);
166 assert(item);
167
168 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
169 xbps_dictionary_t curpkgd;
170 const char *curdep = NULL;
171 char curdepname[XBPS_NAME_SIZE];
172
173 xbps_array_get_cstring_nocopy(rdeps, i, &curdep);
174 if (rpool) {
175 if ((curpkgd = xbps_rpool_get_pkg(xhp, curdep)) == NULL)
176 curpkgd = xbps_rpool_get_virtualpkg(xhp, curdep);
177 } else {
178 if ((curpkgd = xbps_pkgdb_get_pkg(xhp, curdep)) == NULL)
179 curpkgd = xbps_pkgdb_get_virtualpkg(xhp, curdep);
180 /* Ignore missing local runtime dependencies, because ignorepkg */
181 if (curpkgd == NULL)
182 continue;
183 }
184 if (curpkgd == NULL) {
185 /* package depends on missing dependencies */
186 xbps_dbg_printf("%s: missing dependency '%s'\n", pkgver, curdep);
187 errno = ENODEV;
188 return NULL;
189 }
190 if ((!xbps_pkgpattern_name(curdepname, XBPS_NAME_SIZE, curdep)) &&
191 (!xbps_pkg_name(curdepname, XBPS_NAME_SIZE, curdep))) {
192 abort();
193 }
194
195 if (provides && xbps_match_pkgname_in_array(provides, curdepname)) {
196 xbps_dbg_printf("%s: ignoring dependency %s "
197 "already in provides\n", pkgver, curdep);
198 continue;
199 }
200 xitem = lookupItem(curdepname);
201 if (xitem) {
202 add_deps_recursive(xitem, false);
203 continue;
204 }
205 xitem = ordered_depends(xhp, curpkgd, rpool, depth+1);
206 if (xitem == NULL) {
207 /* package depends on missing dependencies */
208 xbps_dbg_printf("%s: missing dependency '%s'\n", pkgver, curdep);
209 errno = ENODEV;
210 return NULL;
211 }
212 assert(xitem);
213 addDepn(item, xitem);
214 }
215 /* all deps were processed, add item to head */
216 if (depth > 0 && !xbps_match_string_in_array(result, item->pkgver)) {
217 str = xbps_string_create_cstring(item->pkgver);
218 assert(str);
219 xbps_array_add_first(result, str);
220 xbps_object_release(str);
221 }
222 return item;
223}
224
225xbps_array_t HIDDEN
226xbps_get_pkg_fulldeptree(struct xbps_handle *xhp, const char *pkg, bool rpool)
227{
228 xbps_dictionary_t pkgd;
229
230 result = xbps_array_create();
231 assert(result);
232
233 if (rpool) {
234 if (((pkgd = xbps_rpool_get_pkg(xhp, pkg)) == NULL) &&
235 ((pkgd = xbps_rpool_get_virtualpkg(xhp, pkg)) == NULL))
236 return NULL;
237 } else {
238 if (((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL) &&
239 ((pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkg)) == NULL))
240 return NULL;
241 }
242 if (ordered_depends(xhp, pkgd, rpool, 0) == NULL)
243 return NULL;
244
245 cleanup();
246 return result;
247}
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:388
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:379
bool xbps_match_pkgname_in_array(xbps_array_t array, const char *pkgname)
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
xbps_dictionary_t xbps_rpool_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:323
xbps_dictionary_t xbps_rpool_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:329
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:253
bool xbps_pkgpattern_name(char *dst, size_t len, const char *pattern)
Definition util.c:289