]>
git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/dependencies.c
1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
27 #include <solv/pool.h>
29 // Enable legacy logging
30 #define PAKFIRE_LEGACY_LOGGING
32 #include <pakfire/dependencies.h>
33 #include <pakfire/logging.h>
34 #include <pakfire/package.h>
35 #include <pakfire/pakfire.h>
36 #include <pakfire/private.h>
37 #include <pakfire/string.h>
38 #include <pakfire/util.h>
40 const struct pakfire_dep pakfire_deps
[] = {
41 { PAKFIRE_PKG_PROVIDES
, "provides" },
42 { PAKFIRE_PKG_PREREQUIRES
, "prerequires" },
43 { PAKFIRE_PKG_REQUIRES
, "requires" },
44 { PAKFIRE_PKG_CONFLICTS
, "conflicts" },
45 { PAKFIRE_PKG_OBSOLETES
, "obsoletes" },
46 { PAKFIRE_PKG_RECOMMENDS
, "recommends" },
47 { PAKFIRE_PKG_SUGGESTS
, "suggests" },
48 { PAKFIRE_PKG_SUPPLEMENTS
, "supplements" },
49 { PAKFIRE_PKG_ENHANCES
, "enhances" },
53 static const struct pakfire_rich_operation
{
56 } pakfire_rich_operations
[] = {
60 { "unless ", REL_UNLESS
},
61 { "else ", REL_ELSE
},
62 { "with ", REL_WITH
},
63 { "without ", REL_WITHOUT
},
68 This function can compare package versions without a Pakfire instance initialized.
70 PAKFIRE_EXPORT
int pakfire_static_version_compare(const char* evr1
, const char* evr2
) {
74 // Initialize the pool
80 pool_setdisttype(pool
, DISTTYPE_RPM
);
83 r
= pool_evrcmp_str(pool
, evr1
, evr2
, EVRCMP_COMPARE
);
91 const char* pakfire_dep2str(struct pakfire
* pakfire
, Id id
) {
92 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
96 return pool_dep2str(pool
, id
);
100 Reads the string until the next space is found.
102 This function considers opening and closing brackets.
104 static size_t skip(const char** s
, const char** n
) {
114 // End on space, newline, =, >, <, or comma
123 // Increment counter on opening bracket
128 // End on the last closing bracket
135 // Move to next character
142 // Return the length of the skipped string
147 This function parses any namespaced dependencies
149 static Id
pakfire_parse_namespace(Pool
* pool
, const char* s
) {
150 const char* p
= strchr(s
, '(');
154 // Store the namespace ID
155 Id
namespace = pool_strn2id(pool
, s
, p
- s
, 1);
157 // Find the end of the string
162 Id id
= pool_strn2id(pool
, p
+ 1, s
- p
- 1, 1);
164 // Bring it all together
165 return pool_rel2id(pool
, namespace, id
, REL_NAMESPACE
, 1);
169 This function parses a simple dependency like "foo = 1.2.3"
171 static Id
pakfire_parse_dep(struct pakfire
* pakfire
, const char** s
) {
180 const char* n
= NULL
;
182 // Ignore empty strings
186 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
188 // Consume any leading space
192 // Find the first part
193 size_t l
= skip(&p
, &n
);
196 if (pakfire_string_startswith(n
, "pakfire(") || pakfire_string_startswith(n
, "arch("))
197 id
= pakfire_parse_namespace(pool
, n
);
199 id
= pool_strn2id(pool
, n
, l
, 1);
201 // Consume any more space
205 if (*p
== '<' || *p
== '=' || *p
== '>') {
221 // Consume any more space
225 // Find the length of EVR
229 if (pakfire_string_startswith(n
, "0:"))
233 Id evr
= pool_strn2id(pool
, n
, l
, 1);
235 // Combine everything
236 id
= pool_rel2id(pool
, id
, evr
, flags
, 1);
239 // Consume any more space
249 This function parses any rich dependencies
251 static Id
pakfire_parse_rich_dep(struct pakfire
* pakfire
, const char** dep
, int flags
) {
252 const char* p
= *dep
;
255 // Do not try parsing empty strings
259 // Must be starting with an opening bracket
260 if (!flags
&& *p
++ != '(')
264 // A new rich dependency
266 id
= pakfire_parse_rich_dep(pakfire
, &p
, 0);
275 // Parse a regular dependency
277 id
= pakfire_parse_dep(pakfire
, &p
);
287 // If we have successfully parsed something, we would expect a closing bracket
293 // Search for a keyword
294 for (const struct pakfire_rich_operation
* op
= pakfire_rich_operations
; op
->keyword
; op
++) {
295 if (pakfire_string_startswith(p
, op
->keyword
)) {
297 p
+= strlen(op
->keyword
);
305 // If there was no keyword, we are done
309 // Parse the next bit
310 Id evr
= pakfire_parse_rich_dep(pakfire
, &p
, flags
);
312 // Abort if there was a problem
316 // Store until where we have parsed the string
319 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
321 // Combine everything
322 return pool_rel2id(pool
, id
, evr
, flags
, 1);
325 Id
pakfire_str2dep(struct pakfire
* pakfire
, const char* dep
) {
334 // Ignore empty strings
340 // Consume any leading space
344 // Ignore any comments
348 // Parse any rich dependencies
350 id
= pakfire_parse_rich_dep(pakfire
, &s
, 0);
352 id
= pakfire_parse_dep(pakfire
, &s
);
354 // Return nothing if we could not parse the entire string
356 DEBUG(pakfire
, "Invalid dependency: %s\n", dep
);
363 int pakfire_str2deps(struct pakfire
* pakfire
, struct pakfire_package
* pkg
,
364 const enum pakfire_package_key key
, const char* deps
) {
368 // Check for valid inputs
372 // Copy deps into a working buffer
373 char* buffer
= strdup(deps
);
377 char* dep
= strtok_r(buffer
, "\n", &p
);
379 // Walk through the buffer line by line
381 // Add the dependency
382 r
= pakfire_package_add_dep(pkg
, key
, dep
);
386 // Move on to next token
387 dep
= strtok_r(NULL
, "\n", &p
);