#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>
return build->flags & flag;
}
+static int __pakfire_build_setup_repo(struct pakfire* pakfire,
+ struct pakfire_repo* repo, void* p) {
+ char path[PATH_MAX];
+ FILE* f = NULL;
+ int r;
+
+ struct pakfire_build* build = (struct pakfire_build*)p;
+
+ // Skip processing the installed repository
+ if (pakfire_repo_is_installed_repo(repo))
+ return 0;
+
+ // Skip processing any other internal repositories
+ if (pakfire_repo_is_internal(repo))
+ return 0;
+
+ const char* name = pakfire_repo_get_name(repo);
+
+ DEBUG(pakfire, "Exporting repository configuration for '%s'\n", name);
+
+ // Make path for configuration file
+ r = pakfire_path(build->pakfire, path, PAKFIRE_CONFIG_DIR "/repos/%s.repo", name);
+ if (r) {
+ ERROR(pakfire, "Could not make repository configuration path for %s: %m\n", name);
+ goto ERROR;
+ }
+
+ // Create the parent directory
+ r = pakfire_mkparentdir(path, 0755);
+ if (r)
+ goto ERROR;
+
+ // Open the repository configuration
+ f = fopen(path, "w");
+ if (!f) {
+ ERROR(pakfire, "Could not open %s for writing: %m\n", path);
+ goto ERROR;
+ }
+
+ // Write repository configuration
+ r = pakfire_repo_write_config(repo, f);
+ if (r) {
+ ERROR(pakfire, "Could not write repository configuration for %s: %m\n", name);
+ goto ERROR;
+ }
+
+ // Bind-mount any local repositories
+ if (pakfire_repo_is_local(repo)) {
+ const char* _path = pakfire_repo_get_path(repo);
+
+ // Bind-mount the repository data read-only
+ r = pakfire_jail_bind(build->jail, _path, _path, MS_RDONLY);
+ if (r) {
+ ERROR(pakfire, "Could not bind-mount the repository at %s: %m\n", _path);
+ goto ERROR;
+ }
+ }
+
+ERROR:
+ if (f)
+ fclose(f);
+
+ return r;
+}
+
/*
This function enables the local repository so that it can be accessed by
a pakfire instance running inside the chroot.
*/
static int pakfire_build_enable_repos(struct pakfire_build* build) {
- return 0;
+ return pakfire_repo_walk(build->pakfire, __pakfire_build_setup_repo, build);
}
/*
return pakfire_jail_shell(build->jail);
}
-static int pakfire_build_run_script(struct pakfire_build* build, const char* filename,
- const char* args[], char** output) {
- char* script = NULL;
- size_t size = 0;
+static int pakfire_build_read_script(struct pakfire_build* build,
+ const char* filename, char** buffer, size_t* length) {
char path[PATH_MAX];
+ FILE* f = NULL;
+ int r;
- DEBUG(build->pakfire, "Running build script '%s'...\n", filename);
+ // Compose the source path
+ r = pakfire_path_join(path, PAKFIRE_SCRIPTS_DIR, filename);
+ if (r) {
+ ERROR(build->pakfire, "Could not compose path for script '%s': %m\n", filename);
+ goto ERROR;
+ }
- // Make the source path
- pakfire_path_join(path, PAKFIRE_SCRIPTS_DIR, filename);
+ DEBUG(build->pakfire, "Reading script from %s...\n", path);
- // Open the source script
- FILE* f = fopen(path, "r");
+ // Open the file
+ f = fopen(path, "r");
if (!f) {
- ERROR(build->pakfire, "Could not open %s: %m\n", path);
- return 1;
+ ERROR(build->pakfire, "Could not open script %s: %m\n", path);
+ goto ERROR;
}
- // Read the script into memory
- int r = pakfire_read_file_into_buffer(f, &script, &size);
+ // Read the file into a the buffer
+ r = pakfire_read_file_into_buffer(f, buffer, length);
if (r) {
- ERROR(build->pakfire, "Could not read script into memory: %m\n");
+ ERROR(build->pakfire, "Could not read script: %m\n");
goto ERROR;
}
+ERROR:
+ if (f)
+ fclose(f);
+
+ return r;
+}
+
+static int pakfire_build_run_script(
+ struct pakfire_build* build,
+ const char* filename,
+ const char* args[],
+ pakfire_jail_communicate_in communicate_in,
+ pakfire_jail_communicate_out communicate_out,
+ void* data) {
+ int r;
+
+ char* script = NULL;
+ size_t length = 0;
+
+ DEBUG(build->pakfire, "Running build script '%s'...\n", filename);
+
+ // Read the script
+ r = pakfire_build_read_script(build, filename, &script, &length);
+ if (r) {
+ ERROR(build->pakfire, "Could not read script %s: %m\n", filename);
+ return r;
+ }
+
// Execute the script
- r = pakfire_jail_exec_script(build->jail, script, size, args, output);
+ r = pakfire_jail_exec_script(build->jail, script, length, args,
+ communicate_in, communicate_out, data);
if (r) {
ERROR(build->pakfire, "Script '%s' failed with status %d\n", filename, r);
}
-ERROR:
if (script)
free(script);
return r;
}
-static int pakfire_build_find_dependencies(struct pakfire_build* build,
- struct pakfire_package* pkg, struct pakfire_filelist* filelist, const char* buildroot) {
- char* provides = NULL;
- char* requires = NULL;
- char path[PATH_MAX];
+struct pakfire_find_deps_ctx {
+ struct pakfire_package* pkg;
+ int dep;
+ struct pakfire_scriptlet* scriptlet;
+ int class;
+ 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);
- // Allocate path to write the filelist to
- int r = pakfire_path(build->pakfire, path, "%s", "/var/tmp/.pakfire-filelist.XXXXXX");
+ // Compile the regular expression
+ r = pakfire_compile_regex(build->pakfire, regex, pattern);
if (r)
- return 1;
+ goto ERROR;
+
+ERROR:
+ if (pattern)
+ free(pattern);
+
+ return r;
+}
- // Create a temporary file
- FILE* f = pakfire_mktemp(path);
- if (!f)
+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;
+ int r = 0;
+
+ const size_t length = pakfire_filelist_size(ctx->filelist);
+
+ // Check if we have reached the end of the filelist
+ if (ctx->i >= length)
+ return EOF;
+
+ // Fetch the next file
+ file = pakfire_filelist_get(ctx->filelist, ctx->i);
+ if (!file) {
+ DEBUG(pakfire, "Could not fetch file %d: %m\n", ctx->i);
+ r = 1;
goto ERROR;
+ }
- // Write filelist to the temporary file
- r = pakfire_filelist_export(filelist, f);
- fclose(f);
- if (r) {
- ERROR(build->pakfire, "Could not export filelist: %m\n");
+ // Fetch the path of the file
+ const char* path = pakfire_file_get_path(file);
+ if (!path) {
+ ERROR(pakfire, "Received a file with an empty path\n");
+ r = 1;
goto ERROR;
}
- const char* root = pakfire_get_path(build->pakfire);
+ // Skip files that don't match what we are looking for
+ if (ctx->class && !pakfire_file_matches_class(file, ctx->class))
+ goto SKIP;
- // Pass buildroot and the filelist as arguments
+ // Write path to stdin
+ r = dprintf(fd, "%s\n", path);
+ if (r < 0)
+ return r;
+
+SKIP:
+ // Move on to the next file
+ ctx->i++;
+
+ // Success
+ r = 0;
+
+ERROR:
+ if (file)
+ pakfire_file_unref(file);
+
+ return r;
+}
+
+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];
+ pcre2_match_data* match = NULL;
+ int r = 0;
+
+ // Nothing to do for an empty buffer
+ if (!buffer || !*buffer)
+ return 0;
+
+ switch (priority) {
+ // Add every dependency that we have received
+ case LOG_INFO:
+ // Copy the dependency to the stack (and remove the trailing newline)
+ r = pakfire_string_format(dep, "%.*s", (int)length - 1, buffer);
+ if (r)
+ return r;
+
+ DEBUG(pakfire, "Processing dependency: %s\n", dep);
+
+ // Filter out any dependencies that are provided by this package
+ if (ctx->dep == PAKFIRE_PKG_REQUIRES) {
+ // If this is a file, we check if it is on the filelist
+ if (pakfire_filelist_contains(ctx->filelist, dep))
+ goto SKIP;
+
+ // Otherwise check if this dependency is provided by this package
+ else if (pakfire_package_matches_dep(ctx->pkg, PAKFIRE_PKG_PROVIDES, dep))
+ 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) {
+ ERROR(pakfire, "Could not process dependency '%s': %m\n", buffer);
+ return r;
+ }
+ break;
+
+ // Send everything else to the default logger
+ default:
+ ERROR(pakfire, "%s\n", buffer);
+ break;
+ }
+
+ goto ERROR;
+
+SKIP:
+ DEBUG(pakfire, "Skipping dependency that is provided by the package itself: %s\n", dep);
+
+ERROR:
+ if (match)
+ pcre2_match_data_free(match);
+
+ return r;
+}
+
+/*
+ This function is a special way to run a script.
+
+ It will pipe the filelist into the standard input of the called script
+ and will read any dependencies from the standard output.
+*/
+static int pakfire_build_find_deps(struct pakfire_build* build,
+ struct pakfire_package* pkg, int dep, const char* script,
+ struct pakfire_filelist* filelist, int class, const pcre2_code* filter) {
+ // Construct the context
+ struct pakfire_find_deps_ctx ctx = {
+ .pkg = pkg,
+ .dep = dep,
+ .class = class,
+ .filter = filter,
+
+ // Filelist
+ .filelist = filelist,
+ .i = 0,
+ };
+ int r;
+
+ // Skip calling the script if class doesn't match
+ if (class && !pakfire_filelist_matches_class(filelist, class)) {
+ DEBUG(build->pakfire, "Skipping calling %s as class does not match\n", script);
+ return 0;
+ }
+
+ // Pass the buildroot as first argument
const char* args[] = {
- buildroot, pakfire_path_relpath(root, path), NULL
+ pakfire_relpath(build->pakfire, build->buildroot),
+ NULL,
};
- // Find all provides
- r = pakfire_build_run_script(build, "find-provides", args, &provides);
+ // Run the script
+ r = pakfire_build_run_script(build, script, args,
+ pakfire_build_send_filelist, pakfire_build_process_deps, &ctx);
+ if (r)
+ ERROR(build->pakfire, "%s returned with error %d\n", script, r);
+
+ return r;
+}
+
+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, "find-provides returned with error %d\n", r);
+ ERROR(build->pakfire, "Provides filter is broken: %m\n");
goto ERROR;
}
- // Find all requires
- r = pakfire_build_run_script(build, "find-requires", args, &requires);
+ // Fetch the requires filter
+ r = pakfire_build_make_filter(build, &filter_requires,
+ makefile, namespace, "filter_requires");
if (r) {
- ERROR(build->pakfire, "find-requires returned with error %d\n", r);
+ ERROR(build->pakfire, "Requires filter is broken: %m\n");
goto ERROR;
}
- // Add all provides to the package
- if (provides) {
- r = pakfire_str2deps(build->pakfire, pkg, PAKFIRE_PKG_PROVIDES, provides);
- if (r) {
- ERROR(build->pakfire, "Could not add provides: %m\n");
- goto ERROR;
- }
- }
+ // Find all provides
+ r = pakfire_build_find_deps(build, pkg,
+ PAKFIRE_PKG_PROVIDES, "find-provides", filelist, 0, filter_provides);
+ if (r)
+ goto ERROR;
- // Add all requires to the package
- if (requires) {
- r = pakfire_str2deps(build->pakfire, pkg, PAKFIRE_PKG_REQUIRES, requires);
- if (r) {
- ERROR(build->pakfire, "Could not add provides: %m\n");
- goto ERROR;
- }
- }
+ // Find all Perl provides
+ r = pakfire_build_find_deps(build, pkg,
+ PAKFIRE_PKG_PROVIDES, "perl.prov", filelist, PAKFIRE_FILE_PERL, filter_provides);
+ if (r)
+ goto ERROR;
- // Success
- r = 0;
+ // Find all requires
+ r = pakfire_build_find_deps(build, pkg,
+ PAKFIRE_PKG_REQUIRES, "find-requires", filelist, 0, filter_requires);
+ if (r)
+ goto ERROR;
+
+ // Find all Perl requires
+ r = pakfire_build_find_deps(build, pkg,
+ PAKFIRE_PKG_REQUIRES, "perl.req", filelist, PAKFIRE_FILE_PERL, filter_requires);
+ if (r)
+ goto ERROR;
ERROR:
- if (provides)
- free(provides);
- if (requires)
- free(requires);
- unlink(path);
+ if (filter_provides)
+ pcre2_code_free(filter_provides);
+ if (filter_requires)
+ pcre2_code_free(filter_requires);
return r;
}
-static int append_to_array(const char*** array, const char* s) {
+static int append_to_array(char*** array, const char* s) {
unsigned int length = 0;
// Determine the length of the existing array
if (*array) {
- for (const char** element = *array; *element; element++)
+ for (char** element = *array; *element; element++)
length++;
}
if (!*array)
return 1;
- // Append s and terminate the array
- (*array)[length] = s;
+ // Copy the string to the heap
+ char* p = strdup(s);
+ if (!p)
+ return 1;
+
+ // Append p and terminate the array
+ (*array)[length] = p;
(*array)[length + 1] = NULL;
return 0;
struct pakfire_filelist* filelist = NULL;
int r = 1;
- char** files = NULL;
- const char** includes = NULL;
- const char** excludes = NULL;
+ char** includes = NULL;
+ char** excludes = NULL;
+ char* p = NULL;
// Fetch filelist from makefile
- files = pakfire_parser_get_split(makefile, namespace, "files", '\n');
+ char* files = pakfire_parser_get(makefile, namespace, "files");
// No files to package?
if (!files)
return 0;
+ const char* file = strtok_r(files, " \n", &p);
+
// Split into includes and excludes
- for (char** file = files; *file; file++) {
- if (**file == '!')
- r = append_to_array(&excludes, *file);
+ while (file) {
+ if (*file == '!')
+ r = append_to_array(&excludes, file + 1);
else
- r = append_to_array(&includes, *file);
+ r = append_to_array(&includes, file);
if (r)
goto ERROR;
+
+ // Move on to the next token
+ file = strtok_r(NULL, " \n", &p);
}
// Allocate a new filelist
goto ERROR;
// Scan for files
- r = pakfire_filelist_scan(filelist, build->buildroot, includes, excludes);
+ r = pakfire_filelist_scan(filelist, build->buildroot,
+ (const char**)includes, (const char**)excludes);
if (r)
goto ERROR;
if (!length)
goto ERROR;
+ // Dump the filelist
+ pakfire_filelist_dump(filelist, 1);
+
// Find dependencies
- r = pakfire_build_find_dependencies(build, pkg, filelist, buildroot);
+ r = pakfire_build_find_dependencies(build, makefile, namespace, pkg, filelist);
if (r) {
ERROR(build->pakfire, "Finding dependencies failed: %m\n");
goto ERROR;
ERROR:
if (filelist)
pakfire_filelist_unref(filelist);
- if (files) {
- for (char** file = files; *file; file++)
- free(*file);
+ if (files)
free(files);
- }
- if (includes)
+ if (includes) {
+ for (char** include = includes; *include; include++)
+ free(*include);
free(includes);
- if (excludes)
+ }
+ if (excludes) {
+ for (char** exclude = excludes; *exclude; exclude++)
+ free(*exclude);
free(excludes);
+ }
return r;
}
-static int pakfire_build_add_scriptlet_requires(struct pakfire_build* build,
- struct pakfire_package* pkg, struct pakfire_scriptlet* scriptlet) {
- char* prerequires = NULL;
- char path[PATH_MAX];
- size_t size;
- int r;
+static int pakfire_build_send_scriptlet(struct pakfire* pakfire, void* data, int fd) {
+ const struct pakfire_find_deps_ctx* ctx = (struct pakfire_find_deps_ctx*)data;
+ size_t length = 0;
- const char* root = pakfire_get_path(build->pakfire);
-
- // Make filename
- r = pakfire_path(build->pakfire, path, "%s", "/var/tmp/.pakfire-scriptlet.XXXXXX");
- if (r)
- return r;
-
- // Fetch scriptlet payload
- const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
-
- // Create a temporary file
- FILE* f = pakfire_mktemp(path);
- if (!f)
+ // Fetch the scriptlet
+ const char* p = pakfire_scriptlet_get_data(ctx->scriptlet, &length);
+ if (!p) {
+ ERROR(pakfire, "Could not fetch scriptlet: %m\n");
return 1;
+ }
- // Write scriptlet
- ssize_t bytes_written = fwrite(data, 1, size, f);
+ // Write it into the pipe
+ ssize_t bytes_written = write(fd, p, length);
if (bytes_written < 0) {
- ERROR(build->pakfire, "Could not write to %s: %m\n", path);
- fclose(f);
- goto ERROR;
+ ERROR(pakfire, "Could not send scriptlet: %m\n");
+ return 1;
}
- // Close file
- fclose(f);
+ return EOF;
+}
+
+static int pakfire_build_add_scriptlet_requires(struct pakfire_build* build,
+ struct pakfire_package* pkg, struct pakfire_scriptlet* scriptlet) {
+ int r;
- // Build commandline
- const char* args[] = {
- pakfire_path_relpath(root, path),
- NULL,
+ struct pakfire_find_deps_ctx ctx = {
+ .pkg = pkg,
+ .dep = PAKFIRE_PKG_PREREQUIRES,
+ .scriptlet = scriptlet,
};
// Find all pre-requires
- r = pakfire_build_run_script(build, "find-prerequires", args, &prerequires);
+ r = pakfire_build_run_script(build, "find-prerequires", NULL,
+ pakfire_build_send_scriptlet, pakfire_build_process_deps, &ctx);
if (r)
goto ERROR;
- // Add all pre-requires to the package
- if (prerequires) {
- r = pakfire_str2deps(build->pakfire, pkg, PAKFIRE_PKG_PREREQUIRES, prerequires);
- if (r) {
- ERROR(build->pakfire, "Could not add pre-requires: %m\n");
- goto ERROR;
- }
- }
-
ERROR:
- if (r && *path)
- unlink(path);
- if (prerequires)
- free(prerequires);
return r;
}
}
// Run the script
- r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, NULL);
+ r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, NULL, NULL, NULL);
if (r) {
ERROR(build->pakfire, "Build stage '%s' failed with status %d\n", stage, r);
}
return r;
}
+/*
+ This helper function takes a callback which is expected to add any files
+ to the given filelist which will be all removed after.
+*/
+static int pakfire_build_post_remove_files(struct pakfire_build* build,
+ struct pakfire_filelist* filelist, const char* description,
+ int (*callback)(struct pakfire* pakfire, struct pakfire_file* file, void* data)) {
+ struct pakfire_filelist* removees = NULL;
+ int r;
+
+ // Create a filelist with objects that need to be removed
+ r = pakfire_filelist_create(&removees, build->pakfire);
+ if (r)
+ goto ERROR;
+
+ // Find all files that need to be removed
+ r = pakfire_filelist_walk(filelist, callback, removees);
+ if (r)
+ goto ERROR;
+
+ if (!pakfire_filelist_is_empty(removees)) {
+ if (description)
+ INFO(build->pakfire, "%s\n", description);
+
+ // Show all files which will be removed
+ pakfire_filelist_dump(removees, 0);
+
+ // Remove all files on the removee list
+ r = pakfire_filelist_cleanup(removees);
+ if (r)
+ goto ERROR;
+
+ // Remove all files from the filelist
+ r = pakfire_filelist_remove_all(filelist, removees);
+ if (r)
+ goto ERROR;
+ }
+
+ERROR:
+ if (removees)
+ pakfire_filelist_unref(removees);
+
+ return r;
+}
+
+static int __pakfire_build_remove_static_libraries(
+ struct pakfire* pakfire, struct pakfire_file* file, void* data) {
+ struct pakfire_filelist* removees = (struct pakfire_filelist*)data;
+
+ // Find all static libraries
+ if (pakfire_file_matches_class(file, PAKFIRE_FILE_STATIC_LIBRARY))
+ return pakfire_filelist_append(removees, file);
+
+ return 0;
+}
+
+static int pakfire_build_post_remove_static_libraries(
+ struct pakfire_build* build, struct pakfire_filelist* filelist) {
+ return pakfire_build_post_remove_files(build, filelist,
+ "Removing static libaries...", __pakfire_build_remove_static_libraries);
+}
+
+static int __pakfire_build_remove_libtool_archives(
+ struct pakfire* pakfire, struct pakfire_file* file, void* data) {
+ struct pakfire_filelist* removees = (struct pakfire_filelist*)data;
+
+ // Find all libtool archive files
+ if (pakfire_file_matches_class(file, PAKFIRE_FILE_LIBTOOL_ARCHIVE))
+ return pakfire_filelist_append(removees, file);
+
+ return 0;
+}
+
+static int pakfire_build_post_remove_libtool_archives(
+ struct pakfire_build* build, struct pakfire_filelist* filelist) {
+ return pakfire_build_post_remove_files(build, filelist,
+ "Removing libtool archives...", __pakfire_build_remove_libtool_archives);
+}
+
+static int pakfire_build_run_post_build_checks(struct pakfire_build* build) {
+ struct pakfire_filelist* filelist = NULL;
+ int r;
+
+ // Create a filelist of all files in the build
+ r = pakfire_filelist_create(&filelist, build->pakfire);
+ if (r) {
+ ERROR(build->pakfire, "Could not create filelist: %m\n");
+ goto ERROR;
+ }
+
+ // Scan for all files in BUILDROOT
+ r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL);
+ if (r)
+ goto ERROR;
+
+ const size_t length = pakfire_filelist_size(filelist);
+
+ // If the filelist is empty, we can are done
+ if (length == 0) {
+ DEBUG(build->pakfire, "Empty BUILDROOT. Skipping post build checks...\n");
+ r = 0;
+ goto ERROR;
+ }
+
+ // Remove any static libraries
+ r = pakfire_build_post_remove_static_libraries(build, filelist);
+ if (r)
+ goto ERROR;
+
+ // Remove any libtool archives
+ r = pakfire_build_post_remove_libtool_archives(build, filelist);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (filelist)
+ pakfire_filelist_unref(filelist);
+
+ return r;
+}
+
static const char* post_build_scripts[] = {
- "remove-static-libs",
"check-symlinks",
"check-unsafe-files",
"check-libraries",
// Run them one by one
for (const char** script = post_build_scripts; *script; script++) {
- int r = pakfire_build_run_script(build, *script, args, NULL);
+ int r = pakfire_build_run_script(build, *script, args, NULL, NULL, NULL);
if (r)
return r;
}
}
static int pakfire_build_setup_repo(struct pakfire_build* build) {
- char path[PATH_MAX] = "/var/tmp/.pakfire-build-repo.XXXXXX";
+ char path[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-build-repo.XXXXXX";
char url[PATH_MAX];
int r;
static int pakfire_build_install_packages(struct pakfire_build* build,
int* snapshot_needs_update) {
- char** packages = NULL;
- int r = 1;
-
- // Fetch configuration
- struct pakfire_config* config = pakfire_get_config(build->pakfire);
- if (!config) {
- ERROR(build->pakfire, "Could not fetch configuration: %m\n");
- r = 1;
- goto ERROR;
- }
-
- // Fetch build environment
- const char* requires = pakfire_config_get(config, "build", "requires", NULL);
- if (!requires) {
- ERROR(build->pakfire, "No build requirements have been defined\n");
- goto ERROR;
- }
+ int r;
- // Split requirements into packages
- packages = pakfire_string_split(requires, ',');
- if (!packages)
- goto ERROR;
+ const char* packages[] = {
+ "build-essential",
+ NULL,
+ };
int changed = 0;
// Install everything
- r = pakfire_install(build->pakfire, 0, 0, (const char**)packages, NULL, 0,
+ r = pakfire_install(build->pakfire, 0, 0, packages, NULL, 0,
&changed, NULL, NULL);
if (r) {
ERROR(build->pakfire, "Could not install build dependencies: %m\n");
- goto ERROR;
+ return r;
}
// Mark snapshot as changed if new packages were installed
r = pakfire_sync(build->pakfire, 0, 0, &changed, NULL, NULL);
if (r) {
ERROR(build->pakfire, "Could not update packages: %m\n");
- goto ERROR;
+ return r;
}
// Has anything changed?
if (changed)
*snapshot_needs_update = 1;
- // Success
- r = 0;
-
-ERROR:
- if (config)
- pakfire_config_unref(config);
-
- if (packages) {
- for (char** package = packages; *package; package++)
- free(*package);
- free(packages);
- }
-
- return r;
+ return 0;
}
/*
if (r)
goto ERROR;
+ // Run post build checks
+ r = pakfire_build_run_post_build_checks(build);
+ if (r)
+ goto ERROR;
+
// Run post build scripts
r = pakfire_build_run_post_build_scripts(build);
if (r)
ERROR:
// Drop to a shell for debugging
- if (pakfire_has_flag(build->pakfire, PAKFIRE_BUILD_INTERACTIVE))
+ if (pakfire_build_has_flag(build, PAKFIRE_BUILD_INTERACTIVE))
pakfire_build_shell(build);
return r;
struct pakfire_package* pkg, void* p) {
struct pakfire_request* request = (struct pakfire_request*)p;
- return pakfire_request_install_package(request, pkg);
+ return pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg,
+ PAKFIRE_REQUEST_ESSENTIAL);
}
static int pakfire_build_install_test(struct pakfire_build* build) {
r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, request);
// Solve the request
- r = pakfire_request_solve(request, NULL, NULL);
+ r = pakfire_request_solve(request);
switch (r) {
// All okay
case 0:
return r;
}
+static int pakfire_build_install_source_package(
+ struct pakfire_build* build, struct pakfire_package* package) {
+ struct pakfire_request* request = NULL;
+ struct pakfire_transaction* transaction = NULL;
+ int r;
+
+ // Create a new request
+ r = pakfire_request_create(&request, build->pakfire, 0);
+ if (r)
+ goto ERROR;
+
+ // Add the package
+ r = pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, package,
+ PAKFIRE_REQUEST_ESSENTIAL);
+ if (r)
+ goto ERROR;
+
+ // Solve the request
+ r = pakfire_request_solve(request);
+ if (r)
+ goto ERROR;
+
+ // Fetch the transaction
+ r = pakfire_request_get_transaction(request, &transaction);
+ if (r)
+ goto ERROR;
+
+ // Set how many packages have been changed
+ const size_t changes = pakfire_transaction_count(transaction);
+
+ // Sanity check to see if we actually try to install anything
+ if (!changes) {
+ ERROR(build->pakfire, "The source package did not get installed\n");
+ r = 1;
+ goto ERROR;
+ }
+
+ // Run the transaction
+ r = pakfire_transaction_run(transaction, 0);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (request)
+ pakfire_request_unref(request);
+
+ return r;
+}
+
PAKFIRE_EXPORT int pakfire_build_exec(struct pakfire_build* build, const char* path) {
- struct pakfire_archive* archive = NULL;
struct pakfire_package* package = NULL;
struct pakfire_parser* makefile = NULL;
char* buildroot = NULL;
int r;
// Set buildroot
- r = pakfire_path(build->pakfire, build->buildroot, "%s", "/var/tmp/.pakfire-buildroot.XXXXXX");
+ r = pakfire_path(build->pakfire, build->buildroot, "%s",
+ PAKFIRE_TMP_DIR "/pakfire-buildroot.XXXXXX");
if (r)
goto ERROR;
- // Open source archive
- r = pakfire_archive_open(&archive, build->pakfire, path);
- if (r) {
- ERROR(build->pakfire, "Could not open source archive %s: %m\n", path);
- goto ERROR;
- }
-
- // Fetch package metadata
- r = pakfire_archive_make_package(archive, NULL, &package);
- if (r) {
- ERROR(build->pakfire, "Could not read package metadata: %m\n");
+ // Open the source package
+ r = pakfire_commandline_add(build->pakfire, path, &package);
+ if (r)
goto ERROR;
- }
const char* nevra = pakfire_package_get_string(package, PAKFIRE_PKG_NEVRA);
if (r)
goto ERROR;
- const char* packages[] = {
- path, NULL
- };
-
- // Install the package into the build environment
- r = pakfire_install(build->pakfire, 0, 0, packages, NULL, PAKFIRE_REQUEST_ESSENTIAL,
- NULL, NULL, NULL);
+ // Install the source package
+ r = pakfire_build_install_source_package(build, package);
if (r) {
- ERROR(build->pakfire, "Could not install %s\n", path);
+ ERROR(build->pakfire, "Could not install the source package: %m\n");
goto ERROR;
}
ERROR:
if (makefile)
pakfire_parser_unref(makefile);
- if (archive)
- pakfire_archive_unref(archive);
if (package)
pakfire_package_unref(package);
This is a convenience function that sets up a build environment and
then drops the user into an interactive shell.
*/
-PAKFIRE_EXPORT int pakfire_shell(struct pakfire* pakfire, const char** packages) {
+PAKFIRE_EXPORT int pakfire_shell(struct pakfire* pakfire, const char** packages, int flags) {
struct pakfire_build* build = NULL;
int r;
+ // Shells are always interactive
+ flags |= PAKFIRE_BUILD_INTERACTIVE;
+
// Create a new build environment
- r = pakfire_build_create(&build, pakfire, NULL, PAKFIRE_BUILD_INTERACTIVE);
+ r = pakfire_build_create(&build, pakfire, NULL, flags);
if (r) {
ERROR(pakfire, "Could not create build: %m\n");
goto ERROR;