]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
build: Implement filter_provides/filter_requires
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 8 Jan 2023 13:28:36 +0000 (13:28 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 8 Jan 2023 13:28:36 +0000 (13:28 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/build.c

index 112d842bfa76d8200720d24aee431af68fe02520..57da89d73502dd69f43b04ec51f98397543d3d5b 100644 (file)
@@ -24,6 +24,9 @@
 #include <unistd.h>
 #include <uuid/uuid.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include <pakfire/build.h>
 #include <pakfire/cgroup.h>
 #include <pakfire/dependencies.h>
@@ -263,11 +266,38 @@ struct pakfire_find_deps_ctx {
        int dep;
        struct pakfire_scriptlet* scriptlet;
        const char* pattern;
+       const pcre2_code* filter;
 
        struct pakfire_filelist* filelist;
        unsigned int i;
 };
 
+static int pakfire_build_make_filter(struct pakfire_build* build, pcre2_code** regex,
+               struct pakfire_parser* makefile, const char* namespace, const char* filter) {
+       char* pattern = NULL;
+       int r = 0;
+
+       // Fetch the pattern
+       pattern = pakfire_parser_get(makefile, namespace, filter);
+
+       // Nothing if to if there is no or an empty pattern
+       if (!pattern || !*pattern)
+               goto ERROR;
+
+       DEBUG(build->pakfire, "Found filter for %s: %s\n", filter, pattern);
+
+       // Compile the regular expression
+       r = pakfire_compile_regex(build->pakfire, regex, pattern);
+       if (r)
+               goto ERROR;
+
+ERROR:
+       if (pattern)
+               free(pattern);
+
+       return r;
+}
+
 static int pakfire_build_send_filelist(struct pakfire* pakfire, void* data, int fd) {
        struct pakfire_find_deps_ctx* ctx = (struct pakfire_find_deps_ctx*)data;
        struct pakfire_file* file = NULL;
@@ -322,7 +352,8 @@ static int pakfire_build_process_deps(struct pakfire* pakfire,
                void* data, int priority, const char* buffer, const size_t length) {
        const struct pakfire_find_deps_ctx* ctx = (struct pakfire_find_deps_ctx*)data;
        char dep[PATH_MAX];
-       int r;
+       pcre2_match_data* match = NULL;
+       int r = 0;
 
        // Nothing to do for an empty buffer
        if (!buffer || !*buffer)
@@ -349,6 +380,46 @@ static int pakfire_build_process_deps(struct pakfire* pakfire,
                                        goto SKIP;
                        }
 
+                       // Check if this dependency should be filtered
+                       if (ctx->filter) {
+                               match = pcre2_match_data_create_from_pattern(ctx->filter, NULL);
+                               if (!match) {
+                                       ERROR(pakfire, "Could not allocate PCRE match data: %m\n");
+                                       goto ERROR;
+                               }
+
+                               // Perform matching
+                               r = pcre2_jit_match(ctx->filter, (PCRE2_SPTR)dep, length - 1,
+                                       0, 0, match, NULL);
+
+                               // No match
+                               if (r == PCRE2_ERROR_NOMATCH) {
+                                       // Fall through...
+
+                               // Handle any errors
+                               } else if (r < 0) {
+                                       char error[120];
+
+                                       // Fetch the error message
+                                       r = pcre2_get_error_message(r, (PCRE2_UCHAR*)error, sizeof(error));
+                                       if (r < 0) {
+                                               ERROR(pakfire, "Could not fetch PCRE error message: %m\n");
+                                               r = 1;
+                                               goto ERROR;
+                                       }
+
+                                       ERROR(pakfire, "Could not match the filter: %s\n", error);
+                                       r = 1;
+                                       goto ERROR;
+
+                               // Match!
+                               } else {
+                                       DEBUG(pakfire, "Skipping dependency that has been filtered: %s\n", dep);
+                                       r = 0;
+                                       goto ERROR;
+                               }
+                       }
+
                        // Add dependency
                        r = pakfire_package_add_dep(ctx->pkg, ctx->dep, buffer);
                        if (r) {
@@ -363,12 +434,16 @@ static int pakfire_build_process_deps(struct pakfire* pakfire,
                        break;
        }
 
-       return 0;
+       goto ERROR;
 
 SKIP:
        DEBUG(pakfire, "Skipping dependency that is provided by the package itself: %s\n", dep);
 
-       return 0;
+ERROR:
+       if (match)
+               pcre2_match_data_free(match);
+
+       return r;
 }
 
 /*
@@ -379,13 +454,14 @@ SKIP:
 */
 static int pakfire_build_find_deps(struct pakfire_build* build,
                struct pakfire_package* pkg, int dep, const char* script,
-               struct pakfire_filelist* filelist, const char* pattern) {
+               struct pakfire_filelist* filelist, const char* pattern, const pcre2_code* filter) {
 
        // Construct the context
        struct pakfire_find_deps_ctx ctx = {
                .pkg      = pkg,
                .dep      = dep,
                .pattern  = pattern,
+               .filter   = filter,
 
                // Filelist
                .filelist = filelist,
@@ -409,34 +485,59 @@ static int pakfire_build_find_deps(struct pakfire_build* build,
 }
 
 static int pakfire_build_find_dependencies(struct pakfire_build* build,
+               struct pakfire_parser* makefile, const char* namespace,
                struct pakfire_package* pkg, struct pakfire_filelist* filelist) {
+       pcre2_code* filter_provides = NULL;
+       pcre2_code* filter_requires = NULL;
        int r;
 
+       // Fetch the provides filter
+       r = pakfire_build_make_filter(build, &filter_provides,
+               makefile, namespace, "filter_provides");
+       if (r) {
+               ERROR(build->pakfire, "Provides filter is broken: %m\n");
+               goto ERROR;
+       }
+
+       // Fetch the requires filter
+       r = pakfire_build_make_filter(build, &filter_requires,
+               makefile, namespace, "filter_requires");
+       if (r) {
+               ERROR(build->pakfire, "Requires filter is broken: %m\n");
+               goto ERROR;
+       }
+
        // Find all provides
        r = pakfire_build_find_deps(build, pkg,
-               PAKFIRE_PKG_PROVIDES, "find-provides", filelist, NULL);
+               PAKFIRE_PKG_PROVIDES, "find-provides", filelist, NULL, filter_provides);
        if (r)
-               return r;
+               goto ERROR;
 
        // Find all Perl provides
        r = pakfire_build_find_deps(build, pkg,
-               PAKFIRE_PKG_PROVIDES, "perl.prov", filelist, "*.pm");
+               PAKFIRE_PKG_PROVIDES, "perl.prov", filelist, "*.pm", filter_provides);
        if (r)
-               return r;
+               goto ERROR;
 
        // Find all requires
        r = pakfire_build_find_deps(build, pkg,
-               PAKFIRE_PKG_REQUIRES, "find-requires", filelist, NULL);
+               PAKFIRE_PKG_REQUIRES, "find-requires", filelist, NULL, filter_requires);
        if (r)
-               return r;
+               goto ERROR;
 
        // Find all Perl requires
        r = pakfire_build_find_deps(build, pkg,
-               PAKFIRE_PKG_REQUIRES, "perl.req", filelist, "*.pm");
+               PAKFIRE_PKG_REQUIRES, "perl.req", filelist, "*.pm", filter_requires);
        if (r)
-               return r;
+               goto ERROR;
 
-       return 0;
+ERROR:
+       if (filter_provides)
+               pcre2_code_free(filter_provides);
+       if (filter_requires)
+               pcre2_code_free(filter_requires);
+
+       return r;
 }
 
 static int append_to_array(char*** array, const char* s) {
@@ -519,7 +620,7 @@ static int pakfire_build_package_add_files(struct pakfire_build* build,
        pakfire_filelist_dump(filelist, 1);
 
        // Find dependencies
-       r = pakfire_build_find_dependencies(build, pkg, filelist);
+       r = pakfire_build_find_dependencies(build, makefile, namespace, pkg, filelist);
        if (r) {
                ERROR(build->pakfire, "Finding dependencies failed: %m\n");
                goto ERROR;