#include <pakfire/build.h>
#include <pakfire/cgroup.h>
+#include <pakfire/config.h>
+#include <pakfire/ctx.h>
#include <pakfire/dependencies.h>
#include <pakfire/dist.h>
#include <pakfire/file.h>
#include <pakfire/package.h>
#include <pakfire/packager.h>
#include <pakfire/parser.h>
+#include <pakfire/path.h>
#include <pakfire/private.h>
#include <pakfire/problem.h>
#include <pakfire/repo.h>
-#include <pakfire/request.h>
#include <pakfire/scriptlet.h>
#include <pakfire/snapshot.h>
#include <pakfire/solution.h>
#include <pakfire/string.h>
+#include <pakfire/transaction.h>
#include <pakfire/util.h>
#define CCACHE_DIR "/var/cache/ccache"
};
struct pakfire_build {
+ struct pakfire_ctx* ctx;
struct pakfire* pakfire;
int nrefs;
char target[PATH_MAX];
// Times
- time_t time_start;
+ struct timespec time_start;
// cgroup
struct pakfire_cgroup* cgroup;
// States
int init:1;
+
+ // Callbacks
+ struct pakfire_build_callbacks {
+ // Log callback
+ pakfire_build_log_callback log;
+ void* log_data;
+ } callbacks;
};
#define TEMPLATE \
"\n" \
"exit 0\n"
+/*
+ Convenience macro to call the logger callback
+*/
+static int pakfire_build_log(struct pakfire_build* build, int priority, int error,
+ const char* file, int line, const char* function, const char* format, ...) {
+ char* buffer = NULL;
+ va_list args;
+ int r;
+
+ // Don't log messages of a lower loglevel
+ if (pakfire_ctx_get_log_level(build->ctx) < priority)
+ return 0;
+
+ // Format message
+ va_start(args, format);
+ r = vasprintf(&buffer, format, args);
+ va_end(args);
+
+ // Fail if we could not format the message
+ if (r < 0)
+ return r;
+
+ // Send everything to the context logger
+ pakfire_ctx_log(build->ctx, priority, file, line, function, "%s", buffer);
+
+ // Call the build logger callback
+ if (build->callbacks.log)
+ r = build->callbacks.log(build, build->callbacks.log_data, priority, error,
+ file, line, function, "%s", buffer);
+ else
+ r = 0;
+
+ // Cleanup
+ if (buffer)
+ free(buffer);
+
+ return r;
+}
+
+#define BUILD_LOG_ERRNO(build, priority, r, arg...) \
+ pakfire_build_log(build, priority, r, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#define BUILD_LOG(build, priority, arg...) BUILD_LOG_ERRNO(build, priority, 0, ## arg)
+
+#define BUILD_INFO_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_INFO, r, ## arg)
+#define BUILD_ERROR_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_ERR, r, ## arg)
+#define BUILD_DEBUG_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_DEBUG, r, ## arg)
+
+#define BUILD_INFO(build, arg...) BUILD_INFO_ERRNO(build, 0, ## arg)
+#define BUILD_ERROR(build, arg...) BUILD_ERROR_ERRNO(build, 0, ## arg)
+#define BUILD_DEBUG(build, arg...) BUILD_DEBUG_ERRNO(build, 0, ## arg)
+
static int pakfire_build_has_flag(struct pakfire_build* build, int flag) {
return build->flags & flag;
}
-static time_t pakfire_build_duration(struct pakfire_build* build) {
+static double pakfire_build_duration(struct pakfire_build* build) {
+ struct timespec now;
+ int r;
+
// What time is it now?
- time_t now = time(NULL);
+ r = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (r < 0)
+ return r;
+
+ return pakfire_timespec_delta(&now, &build->time_start);
+}
+
+static int pakfire_build_jail_log_callback(struct pakfire* pakfire,
+ void* data, int priority, const char* line, size_t length) {
+ struct pakfire_build* build = data;
+
+ // Get the runtime of the build
+ const double t = pakfire_build_duration(build);
+ if (t < 0)
+ return t;
- // Return any errors
- if (now < 0)
- return now;
+ const unsigned int h = (unsigned int)t / 3600;
+ const unsigned int m = (unsigned int)t % 3600 / 60;
+ const unsigned int s = (unsigned int)t % 60;
+ const unsigned int ms = (unsigned int)(t * 1000.0) % 1000;
- return now - build->time_start;
+ if (h)
+ return BUILD_LOG(build, priority, "[%02d:%02d:%02d.%04d] %.*s", h, m, s, ms, length, line);
+
+ else if (m)
+ return BUILD_LOG(build, priority, "[ %02d:%02d.%04d] %.*s", m, s, ms, length, line);
+
+ else
+ return BUILD_LOG(build, priority, "[ %02d.%04d] %.*s", s, ms, length, line);
}
static int __pakfire_build_setup_repo(struct pakfire* pakfire,
const char* name = pakfire_repo_get_name(repo);
- DEBUG(pakfire, "Exporting repository configuration for '%s'\n", name);
+ BUILD_DEBUG(build, "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);
+ BUILD_ERROR(build, "Could not make repository configuration path for %s: %m\n", name);
goto ERROR;
}
// Open the repository configuration
f = fopen(path, "w");
if (!f) {
- ERROR(pakfire, "Could not open %s for writing: %m\n", path);
+ BUILD_ERROR(build, "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);
+ BUILD_ERROR(build, "Could not write repository configuration for %s: %m\n", name);
goto ERROR;
}
if (pakfire_path_exists(_path)) {
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);
+ BUILD_ERROR(build, "Could not bind-mount the repository at %s: %m\n", _path);
goto ERROR;
}
}
int r;
// Compose the source path
- r = pakfire_path_join(path, PAKFIRE_SCRIPTS_DIR, filename);
+ r = pakfire_path_append(path, PAKFIRE_SCRIPTS_DIR, filename);
if (r) {
ERROR(build->pakfire, "Could not compose path for script '%s': %m\n", filename);
goto ERROR;
}
- DEBUG(build->pakfire, "Reading script from %s...\n", path);
+ BUILD_DEBUG(build, "Reading script from %s...\n", path);
// Open the file
f = fopen(path, "r");
if (!f) {
- ERROR(build->pakfire, "Could not open script %s: %m\n", path);
+ BUILD_ERROR(build, "Could not open script %s: %m\n", path);
goto ERROR;
}
// 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: %m\n");
+ BUILD_ERROR(build, "Could not read script: %m\n");
goto ERROR;
}
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) {
+ const char* args[]) {
int r;
char* script = NULL;
size_t length = 0;
- DEBUG(build->pakfire, "Running build script '%s'...\n", filename);
+ BUILD_DEBUG(build, "Running build script '%s'...\n", filename);
// Read the script
r = pakfire_build_read_script(build, filename, &script, &length);
}
// Execute the script
- 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);
- }
+ r = pakfire_jail_exec_script(build->jail, script, length, args);
+ if (r)
+ BUILD_ERROR(build, "Script '%s' failed with status %d\n", filename, r);
if (script)
free(script);
}
struct pakfire_find_deps_ctx {
+ struct pakfire_build* build;
struct pakfire_package* pkg;
int dep;
struct pakfire_scriptlet* scriptlet;
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;
+static int pakfire_build_send_filelist(struct pakfire_ctx* ctx,
+ struct pakfire_jail* jail, void* data, int fd) {
+ struct pakfire_find_deps_ctx* p = (struct pakfire_find_deps_ctx*)data;
struct pakfire_file* file = NULL;
int r = 0;
- const size_t length = pakfire_filelist_length(ctx->filelist);
+ const size_t length = pakfire_filelist_length(p->filelist);
// Check if we have reached the end of the filelist
- if (ctx->i >= length)
+ if (p->i >= length)
return EOF;
// Fetch the next file
- file = pakfire_filelist_get(ctx->filelist, ctx->i);
+ file = pakfire_filelist_get(p->filelist, p->i);
if (!file) {
- DEBUG(pakfire, "Could not fetch file %d: %m\n", ctx->i);
+ CTX_DEBUG(ctx, "Could not fetch file %u: %m\n", p->i);
r = 1;
goto ERROR;
}
// 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");
+ CTX_ERROR(ctx, "Received a file with an empty path\n");
r = 1;
goto ERROR;
}
// Skip files that don't match what we are looking for
- if (ctx->class && !pakfire_file_matches_class(file, ctx->class))
+ if (p->class && !pakfire_file_matches_class(file, p->class))
goto SKIP;
// Write path to stdin
SKIP:
// Move on to the next file
- ctx->i++;
+ p->i++;
// Success
r = 0;
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;
+static int pakfire_build_process_deps(struct pakfire_ctx* ctx, struct pakfire_jail* jail,
+ void* data, const char* buffer, const size_t length) {
+ const struct pakfire_find_deps_ctx* p = (struct pakfire_find_deps_ctx*)data;
char dep[PATH_MAX];
pcre2_match_data* match = NULL;
int r = 0;
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;
+ // 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);
+ BUILD_DEBUG(p->build, "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;
+ // Filter out any dependencies that are provided by this package
+ if (p->dep == PAKFIRE_PKG_REQUIRES) {
+ // If this is a file, we check if it is on the filelist
+ if (pakfire_filelist_contains(p->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;
- }
+ // Otherwise check if this dependency is provided by this package
+ else if (pakfire_package_matches_dep(p->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;
- }
- }
+ // Check if this dependency should be filtered
+ if (p->filter) {
+ match = pcre2_match_data_create_from_pattern(p->filter, NULL);
+ if (!match) {
+ CTX_ERROR(ctx, "Could not allocate PCRE match data: %m\n");
+ 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;
+ // Perform matching
+ r = pcre2_jit_match(p->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) {
+ BUILD_ERROR(p->build, "Could not fetch PCRE error message: %m\n");
+ r = 1;
+ goto ERROR;
}
- break;
- // Send everything else to the default logger
- default:
- ERROR(pakfire, "%s\n", buffer);
- break;
+ BUILD_ERROR(p->build, "Could not match the filter: %s\n", error);
+ r = 1;
+ goto ERROR;
+
+ // Match!
+ } else {
+ BUILD_DEBUG(p->build, "Skipping dependency that has been filtered: %s\n", dep);
+ r = 0;
+ goto ERROR;
+ }
+ }
+
+ // Add dependency
+ r = pakfire_package_add_dep(p->pkg, p->dep, buffer);
+ if (r) {
+ BUILD_ERROR(p->build, "Could not process dependency '%s': %m\n", buffer);
+ return r;
}
goto ERROR;
SKIP:
- DEBUG(pakfire, "Skipping dependency that is provided by the package itself: %s\n", dep);
+ BUILD_DEBUG(p->build, "Skipping dependency that is provided by the package itself: %s\n", dep);
ERROR:
if (match)
struct pakfire_filelist* filelist, int class, const pcre2_code* filter) {
// Construct the context
struct pakfire_find_deps_ctx ctx = {
+ .build = build,
.pkg = pkg,
.dep = dep,
.class = class,
NULL,
};
+ // Set callbacks
+ pakfire_jail_set_stdin_callback(build->jail, pakfire_build_send_filelist, &ctx);
+ pakfire_jail_set_stdout_callback(build->jail, pakfire_build_process_deps, &ctx);
+
// Run the script
- r = pakfire_build_run_script(build, script, args,
- pakfire_build_send_filelist, pakfire_build_process_deps, &ctx);
+ r = pakfire_build_run_script(build, script, args);
if (r)
- ERROR(build->pakfire, "%s returned with error %d\n", script, r);
+ BUILD_ERROR(build, "%s returned with error %d\n", script, r);
return r;
}
// Scan for files
r = pakfire_filelist_scan(filelist, build->buildroot,
- (const char**)includes, (const char**)excludes);
+ (const char**)includes, (const char**)excludes, PAKFIRE_FILELIST_EXTENDED_MATCHING);
if (r)
goto ERROR;
- DEBUG(build->pakfire, "%zu file(s) found\n", pakfire_filelist_length(filelist));
+ BUILD_DEBUG(build, "%zu file(s) found\n", pakfire_filelist_length(filelist));
// Nothing to do if the filelist is empty
if (pakfire_filelist_is_empty(filelist))
// Find dependencies
r = pakfire_build_find_dependencies(build, makefile, namespace, pkg, filelist);
if (r) {
- ERROR(build->pakfire, "Finding dependencies failed: %m\n");
+ BUILD_ERROR(build, "Finding dependencies failed: %m\n");
goto ERROR;
}
return 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;
+static int pakfire_build_send_scriptlet(struct pakfire_ctx* ctx, struct pakfire_jail* jail,
+ void* data, int fd) {
+ const struct pakfire_find_deps_ctx* __ctx = (struct pakfire_find_deps_ctx*)data;
size_t length = 0;
// Fetch the scriptlet
- const char* p = pakfire_scriptlet_get_data(ctx->scriptlet, &length);
+ const char* p = pakfire_scriptlet_get_data(__ctx->scriptlet, &length);
if (!p) {
- ERROR(pakfire, "Could not fetch scriptlet: %m\n");
+ CTX_ERROR(ctx, "Could not fetch scriptlet: %m\n");
return 1;
}
// Write it into the pipe
ssize_t bytes_written = write(fd, p, length);
if (bytes_written < 0) {
- ERROR(pakfire, "Could not send scriptlet: %m\n");
+ CTX_ERROR(ctx, "Could not send scriptlet: %m\n");
return 1;
}
int r;
struct pakfire_find_deps_ctx ctx = {
+ .build = build,
.pkg = pkg,
.dep = PAKFIRE_PKG_PREREQUIRES,
.scriptlet = scriptlet,
};
+ // Set callbacks
+ pakfire_jail_set_stdin_callback(build->jail, pakfire_build_send_scriptlet, &ctx);
+ pakfire_jail_set_stdout_callback(build->jail, pakfire_build_process_deps, &ctx);
+
// Find all pre-requires
- r = pakfire_build_run_script(build, "find-prerequires", NULL,
- pakfire_build_send_scriptlet, pakfire_build_process_deps, &ctx);
+ r = pakfire_build_run_script(build, "find-prerequires", NULL);
if (r)
goto ERROR;
goto ERROR;
// Create a scriptlet
- r = pakfire_scriptlet_create(&scriptlet, build->pakfire, type, shell, 0);
+ r = pakfire_scriptlet_create(&scriptlet, build->ctx, type, shell, 0);
if (r)
goto ERROR;
// Add it to the package
r = pakfire_packager_add_scriptlet(packager, scriptlet);
if (r) {
- ERROR(build->pakfire, "Could not add scriptlet %s\n", type);
+ BUILD_ERROR(build, "Could not add scriptlet %s\n", type);
goto ERROR;
}
// Add scriptlet requirements
r = pakfire_build_add_scriptlet_requires(build, pkg, scriptlet);
if (r) {
- ERROR(build->pakfire, "Could not add scriptlet requirements: %m\n");
+ BUILD_ERROR(build, "Could not add scriptlet requirements: %m\n");
goto ERROR;
}
goto ERROR;
}
- INFO(build->pakfire, "Building package '%s'...\n", name);
- DEBUG(build->pakfire, " buildroot = %s\n", buildroot);
+ BUILD_INFO(build, "Building package '%s'...\n", name);
+ BUILD_DEBUG(build, " buildroot = %s\n", buildroot);
// Fetch build architecture
const char* arch = pakfire_get_arch(build->pakfire);
// Fetch package from makefile
r = pakfire_parser_create_package(makefile, &pkg, NULL, namespace, arch);
if (r) {
- ERROR(build->pakfire, "Could not create package from makefile: %m\n");
+ BUILD_ERROR(build, "Could not create package from makefile: %m\n");
goto ERROR;
}
// Write the finished package
r = pakfire_packager_finish_to_directory(packager, path, NULL);
if (r) {
- ERROR(build->pakfire, "pakfire_packager_finish() failed: %m\n");
+ BUILD_ERROR(build, "pakfire_packager_finish() failed: %m\n");
goto ERROR;
}
return r;
}
-static int pakfire_build_package_dump(struct pakfire* pakfire,
+static int pakfire_build_package_dump(struct pakfire_ctx* ctx,
struct pakfire_package* pkg, void* p) {
+ struct pakfire_build* build = p;
+
char* dump = pakfire_package_dump(pkg, PAKFIRE_PKG_DUMP_LONG);
if (!dump)
return 1;
- INFO(pakfire, "%s\n", dump);
+ BUILD_INFO(build, "%s\n", dump);
free(dump);
return 0;
static int pakfire_build_packages(struct pakfire_build* build,
struct pakfire_parser* makefile) {
- DEBUG(build->pakfire, "Creating packages...");
+ BUILD_INFO(build, "Creating packages...");
int r = 1;
const char* buildroot = pakfire_relpath(build->pakfire, build->buildroot);
// Fetch a list all all packages
char** packages = pakfire_parser_list_namespaces(makefile, "packages.package:*");
if (!packages) {
- ERROR(build->pakfire, "Could not find any packages: %m\n");
+ BUILD_ERROR(build, "Could not find any packages: %m\n");
goto ERROR;
}
for (char** package = packages; *package; package++)
num_packages++;
- DEBUG(build->pakfire, "Found %d package(s)\n", num_packages);
+ DEBUG(build->pakfire, "Found %u package(s)\n", num_packages);
// Build packages in reverse order
for (int i = num_packages - 1; i >= 0; i--) {
goto ERROR;
// Create a new packagelist
- r = pakfire_packagelist_create(&build->packages, build->pakfire);
+ r = pakfire_packagelist_create(&build->packages, build->ctx);
if (r)
goto ERROR;
goto ERROR;
// Dump them all
- r = pakfire_packagelist_walk(build->packages, pakfire_build_package_dump, NULL);
+ r = pakfire_packagelist_walk(build->packages, pakfire_build_package_dump, build);
if (r)
goto ERROR;
// Create the build script
char* script = pakfire_parser_expand(makefile, "build", template);
if (!script) {
- ERROR(build->pakfire, "Could not generate the build script for stage '%s': %m\n",
- stage);
+ BUILD_ERROR(build, "Could not generate the build script for stage '%s': %m\n", stage);
goto ERROR;
}
- INFO(build->pakfire, "Running build stage '%s'\n", stage);
+ BUILD_INFO(build, "Running build stage '%s'\n", stage);
// Import environment
// XXX is this a good idea?
r = pakfire_jail_import_env(build->jail, (const char**)envp);
if (r) {
- ERROR(build->pakfire, "Could not import environment: %m\n");
+ BUILD_ERROR(build, "Could not import environment: %m\n");
goto ERROR;
}
+#warning We are thworing away the output here. Do we want this?
+
// Run the script
- 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);
- }
+ r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL);
+ if (r)
+ BUILD_ERROR(build, "Build stage '%s' failed with status %d\n", stage, r);
ERROR:
if (envp) {
if (!pakfire_filelist_is_empty(removees)) {
if (description)
- INFO(build->pakfire, "%s\n", description);
+ BUILD_INFO(build, "%s\n", description);
// Show all files which will be removed
pakfire_filelist_dump(removees, PAKFIRE_FILE_DUMP_FULL|PAKFIRE_FILE_DUMP_ISSUES);
PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY);
}
-/*
- BUILDROOT Check
-*/
-static int pakfire_build_post_check_buildroot(
- struct pakfire_build* build, struct pakfire_filelist* filelist) {
- const char* buildroot = pakfire_relpath(build->pakfire, build->buildroot);
-
- // Nested function to keep a reference to buildroot
- int __pakfire_build_post_check_buildroot(
- struct pakfire* pakfire, struct pakfire_file* file, void* data) {
- struct pakfire_filelist* matches = (struct pakfire_filelist*)data;
- int r;
-
- // Fetch the path
- const char* path = pakfire_file_get_path(file);
- if (!path)
- return 1;
-
- // Do not run this for Python bytecode files
- if (pakfire_path_match("**.pyc", path))
- return 0;
-
- if (pakfire_file_payload_matches(file, buildroot, strlen(buildroot))) {
- r = pakfire_filelist_add(matches, file);
- if (r)
- return r;
- }
-
- return 0;
- }
-
- return pakfire_build_post_process_files(
- build, filelist, "Files containing BUILDROOT:",
- __pakfire_build_post_check_buildroot, PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY);
-}
-
/*
File Issues
*/
// Check file for issues
r = pakfire_file_check(file, &issues);
if (r) {
- ERROR(pakfire, "%s: File Check failed: %m\n", pakfire_file_get_path(file));
+ //BUILD_ERROR(build, "%s: File Check failed: %m\n", pakfire_file_get_path(file));
return 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");
+ BUILD_ERROR(build, "Could not create filelist: %m\n");
goto ERROR;
}
// Scan for all files in BUILDROOT
- r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL);
+ r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL, 0);
if (r)
goto ERROR;
if (r)
goto ERROR;
- // Check for BUILDROOT
- r = pakfire_build_post_check_buildroot(build, filelist);
- if (r)
- goto ERROR;
-
// Check files
r = pakfire_build_post_check_files(build, filelist);
if (r)
// Run them one by one
for (const char** script = post_build_scripts; *script; script++) {
- int r = pakfire_build_run_script(build, *script, args, NULL, NULL, NULL);
+ int r = pakfire_build_run_script(build, *script, args);
if (r)
return r;
}
pakfire_cgroup_unref(build->cgroup);
}
- pakfire_unref(build->pakfire);
+ if (build->pakfire)
+ pakfire_unref(build->pakfire);
+ if (build->ctx)
+ pakfire_ctx_unref(build->ctx);
free(build);
}
r = uuid_parse(id, build->id);
if (r) {
ERROR(build->pakfire, "Could not parse build ID '%s'\n", id);
- errno = EINVAL;
- return r;
+ return -EINVAL;
}
// Otherwise initialize the Build ID with something random
}
// Create a new cgroup
- r = pakfire_cgroup_open(&build->cgroup, build->pakfire, path,
+ r = pakfire_cgroup_open(&build->cgroup, build->ctx, path,
PAKFIRE_CGROUP_ENABLE_ACCOUNTING);
if (r) {
ERROR(build->pakfire, "Could not create cgroup for build %s: %m\n", build->_id);
return r;
}
+ // Build everything with a slightly lower priority
+ r = pakfire_jail_nice(build->jail, 5);
+ if (r) {
+ ERROR(build->pakfire, "Could not set nice level: %m\n");
+ return r;
+ }
+
// Done
return 0;
}
return 0;
// Check that the path is set
- if (!*build->ccache_path) {
- errno = ENOTSUP;
- return 1;
- }
+ if (!*build->ccache_path)
+ return -ENOTSUP;
// Make sure the path exists
r = pakfire_mkdir(build->ccache_path, 0755);
return 0;
}
+ // Set CCACHE_DIR
+ r = pakfire_jail_set_env(build->jail, "CCACHE_DIR", CCACHE_DIR);
+ if (r) {
+ ERROR(build->pakfire, "Could not set ccache directory: %m\n");
+ return r;
+ }
+
// Set CCACHE_TEMPDIR
r = pakfire_jail_set_env(build->jail, "CCACHE_TEMPDIR", "/tmp");
if (r) {
}
static int pakfire_build_set_time_start(struct pakfire_build* build) {
- const time_t now = time(NULL);
+ int r;
- if (now < 0) {
+ // Fetch current time
+ r = clock_gettime(CLOCK_MONOTONIC, &build->time_start);
+ if (r < 0)
ERROR(build->pakfire, "Could not fetch start time: %m\n");
- return 1;
- }
-
- build->time_start = now;
- return 0;
+ return r;
}
PAKFIRE_EXPORT int pakfire_build_create(struct pakfire_build** build,
if (!b)
return 1;
+ // Reference the context
+ b->ctx = pakfire_ctx(pakfire);
+
// Reference pakfire
b->pakfire = pakfire_ref(pakfire);
return NULL;
}
+PAKFIRE_EXPORT void pakfire_build_set_log_callback(struct pakfire_build* build,
+ pakfire_build_log_callback callback, void* data) {
+ build->callbacks.log = callback;
+ build->callbacks.log_data = data;
+}
+
PAKFIRE_EXPORT int pakfire_build_set_ccache_path(
struct pakfire_build* build, const char* path) {
// Check if this can be called
- if (pakfire_build_has_flag(build, PAKFIRE_BUILD_DISABLE_CCACHE)) {
- errno = EPERM;
- return 1;
- }
+ if (pakfire_build_has_flag(build, PAKFIRE_BUILD_DISABLE_CCACHE))
+ return -EPERM;
// Check input value
- if (!path || !*path) {
- errno = EINVAL;
- return 1;
- }
+ if (!path || !*path)
+ return -EINVAL;
// Store the path
return pakfire_string_set(build->ccache_path, path);
return pakfire_string_set(build->target, target);
}
-static int pakfire_build_install_packages(struct pakfire_build* build,
- int* snapshot_needs_update) {
+static int pakfire_build_install_packages(
+ struct pakfire_build* build, int* snapshot_needs_update) {
+ struct pakfire_transaction* transaction = NULL;
+ char* problems = NULL;
int r;
- int changed = 0;
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, build->pakfire, 0);
+ if (r)
+ goto ERROR;
- // Install everything
- r = pakfire_install(build->pakfire, 0, 0, PAKFIRE_BUILD_PACKAGES, NULL, 0,
- &changed, NULL, NULL);
- if (r) {
- ERROR(build->pakfire, "Could not install build dependencies: %m\n");
- return r;
+ // Install all build dependencies
+ for (const char** p = PAKFIRE_BUILD_PACKAGES; *p; p++) {
+ r = pakfire_transaction_request(transaction,
+ PAKFIRE_JOB_INSTALL, *p, PAKFIRE_JOB_ESSENTIAL);
+ if (r)
+ goto ERROR;
}
- // Mark snapshot as changed if new packages were installed
- if (changed)
- *snapshot_needs_update = 1;
+ // Also update everything that has already been installed
+ r = pakfire_transaction_request(transaction, PAKFIRE_JOB_SYNC, NULL, 0);
+ if (r)
+ goto ERROR;
- // Update everything
- r = pakfire_sync(build->pakfire, 0, 0, &changed, NULL, NULL);
+ // Solve the transaction
+ r = pakfire_transaction_solve(transaction, 0, &problems);
if (r) {
- ERROR(build->pakfire, "Could not update packages: %m\n");
- return r;
+ BUILD_ERROR(build, "Could not install build dependencies:\n%s\n", problems);
+ goto ERROR;
}
- // Has anything changed?
- if (changed)
+ // If there are changes, we have to update the snapshot
+ if (pakfire_transaction_count(transaction))
*snapshot_needs_update = 1;
- return 0;
+ // Run the transaction
+ r = pakfire_transaction_run(transaction);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (problems)
+ free(problems);
+
+ return r;
}
/*
r = pakfire_read_makefile(parser, build->pakfire, path, &error);
if (r) {
if (error) {
- ERROR(build->pakfire, "Could not parse makefile %s: %s\n", path,
+ BUILD_ERROR(build, "Could not parse makefile %s: %s\n", path,
pakfire_parser_error_get_message(error));
} else {
- ERROR(build->pakfire, "Could not parse makefile %s: %m\n", path);
+ BUILD_ERROR(build, "Could not parse makefile %s: %m\n", path);
}
goto ERROR;
// Run post build checks
r = pakfire_build_run_post_build_checks(build);
if (r) {
- ERROR(build->pakfire, "Post build checks failed\n");
+ BUILD_ERROR(build, "Post build checks failed\n");
goto ERROR;
}
static int __pakfire_build_unpackaged_file(struct pakfire* pakfire,
struct pakfire_file* file, void* p) {
+ struct pakfire_build* build = p;
+
char* s = pakfire_file_dump(file, PAKFIRE_FILE_DUMP_FULL);
if (s) {
- ERROR(pakfire, "%s\n", s);
+ BUILD_ERROR(build, "%s\n", s);
free(s);
}
goto ERROR;
// Scan for all files in BUILDROOT
- r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL);
+ r = pakfire_filelist_scan(filelist, build->buildroot, NULL, NULL, 0);
if (r)
goto ERROR;
if (!pakfire_filelist_is_empty(filelist)) {
- ERROR(build->pakfire, "Unpackaged files found:\n");
+ BUILD_ERROR(build, "Unpackaged files found:\n");
- r = pakfire_filelist_walk(filelist, __pakfire_build_unpackaged_file, NULL, 0);
+ r = pakfire_filelist_walk(filelist, __pakfire_build_unpackaged_file, build, 0);
if (r)
goto ERROR;
return r;
}
-static int pakfire_build_install_package(struct pakfire* pakfire,
+static int pakfire_build_install_package(struct pakfire_ctx* ctx,
struct pakfire_package* pkg, void* p) {
- struct pakfire_request* request = (struct pakfire_request*)p;
+ struct pakfire_transaction* transaction = (struct pakfire_transaction*)p;
- return pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg,
- PAKFIRE_REQUEST_ESSENTIAL);
+ return pakfire_transaction_request_package(transaction,
+ PAKFIRE_JOB_INSTALL, pkg, PAKFIRE_JOB_ESSENTIAL);
}
static int pakfire_build_install_test(struct pakfire_build* build) {
- struct pakfire_request* request = NULL;
- struct pakfire_problem* problem = NULL;
- struct pakfire_solution* solution = NULL;
- const char* s = NULL;
+ struct pakfire_transaction* transaction = NULL;
+ char* problems = NULL;
int r;
- // Create a new request
- r = pakfire_request_create(&request, build->pakfire, 0);
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, build->pakfire, 0);
if (r)
goto ERROR;
// Add all packages
- r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, request);
+ r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, transaction);
// Solve the request
- r = pakfire_request_solve(request, 0);
+ r = pakfire_transaction_solve(transaction, PAKFIRE_SOLVE_SHOW_SOLUTIONS, &problems);
switch (r) {
// All okay
case 0:
// Dependency Error
case 2:
- ERROR(build->pakfire, "Install test failed:\n");
-
- // Walk through all problems
- for (;;) {
- r = pakfire_request_next_problem(request, &problem);
- if (r)
- goto ERROR;
-
- // There are no more problems
- if (!problem)
- break;
-
- // Format the problem into something human-readable
- s = pakfire_problem_to_string(problem);
- if (!s)
- continue;
-
- ERROR(build->pakfire, " * %s\n", s);
-
- // Walk through all solutions
- for (;;) {
- r = pakfire_problem_next_solution(problem, &solution);
- if (r)
- goto ERROR;
-
- // There are no more solutions
- if (!solution)
- break;
-
- // Format the solution into something human-readable
- s = pakfire_solution_to_string(solution);
- if (!s)
- continue;
-
- ERROR(build->pakfire, " * %s\n", s);
- }
- }
-
+ BUILD_ERROR(build, "Install test failed:\n%s\n", problems);
break;
// Any other errors
default:
+ BUILD_ERROR(build, "Install test failed: %m\n");
goto ERROR;
}
ERROR:
- if (r)
- ERROR(build->pakfire, "Install test failed: %m\n");
- if (request)
- pakfire_request_unref(request);
- if (problem)
- pakfire_problem_unref(problem);
- if (solution)
- pakfire_solution_unref(solution);
+ if (problems)
+ free(problems);
return r;
}
return 0;
}
-static int pakfire_build_copy_package(struct pakfire* pakfire,
+static int pakfire_build_copy_package(struct pakfire_ctx* ctx,
struct pakfire_package* pkg, void* p) {
struct pakfire_archive* archive = NULL;
char path[PATH_MAX];
const char* target = (const char*)p;
- if (!target) {
- errno = EINVAL;
- return 1;
- }
+ if (!target)
+ return -EINVAL;
// Fetch the package filename
const char* filename = pakfire_package_get_string(pkg, PAKFIRE_PKG_FILENAME);
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;
+ char* problems = NULL;
int r;
- // Create a new request
- r = pakfire_request_create(&request, build->pakfire, 0);
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, 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;
-
- // Install all essential packages
+ // Request to install all essential packages
for (const char** p = PAKFIRE_BUILD_PACKAGES; *p; p++) {
- r = pakfire_request_add(request, PAKFIRE_REQ_INSTALL, *p, PAKFIRE_REQUEST_ESSENTIAL);
+ r = pakfire_transaction_request(transaction,
+ PAKFIRE_JOB_INSTALL, *p, PAKFIRE_JOB_ESSENTIAL);
if (r)
goto ERROR;
}
- // Solve the request
- r = pakfire_request_solve(request, 0);
+ // Add the source package
+ r = pakfire_transaction_request_package(transaction,
+ PAKFIRE_JOB_INSTALL, package, PAKFIRE_JOB_ESSENTIAL);
if (r)
goto ERROR;
- // Fetch the transaction
- r = pakfire_request_get_transaction(request, &transaction);
- if (r)
+ // Solve the transaction
+ r = pakfire_transaction_solve(transaction, 0, &problems);
+ if (r) {
+ if (problems)
+ BUILD_ERROR(build, "Could not install the source package:\n%s\n", problems);
+
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");
+ BUILD_ERROR(build, "The source package did not get installed\n");
r = 1;
goto ERROR;
}
// Run the transaction
- r = pakfire_transaction_run(transaction, 0);
+ r = pakfire_transaction_run(transaction);
if (r)
goto ERROR;
ERROR:
if (transaction)
pakfire_transaction_unref(transaction);
- if (request)
- pakfire_request_unref(request);
+ if (problems)
+ free(problems);
return r;
}
struct pakfire_package* package = NULL;
struct pakfire_parser* makefile = NULL;
char* buildroot = NULL;
+ char* problems = NULL;
char duration[TIME_STRING_MAX];
int r;
+ // Fetch architecture
+ const char* arch = pakfire_get_arch(build->pakfire);
+
// Set buildroot
r = pakfire_path(build->pakfire, build->buildroot, "%s",
PAKFIRE_TMP_DIR "/pakfire-buildroot.XXXXXX");
goto ERROR;
const char* nevra = pakfire_package_get_string(package, PAKFIRE_PKG_NEVRA);
+ const char* uuid = pakfire_package_get_string(package, PAKFIRE_PKG_UUID);
+
+ BUILD_INFO(build, "Building %s (%s)...\n", nevra, uuid);
- INFO(build->pakfire, "Building %s...\n", nevra);
+ // Check if this package can be build in this environment
+ if (!pakfire_package_supports_build_arch(package, arch)) {
+ ERROR(build->pakfire, "%s does not support being built on %s\n", nevra, arch);
+ r = -ENOTSUP;
+ goto ERROR;
+ }
+
+ // Perform an install check to see whether we can build this at all
+ r = pakfire_package_installcheck(package, &problems, 0);
+ if (r) {
+ BUILD_ERROR(build, "Cannot build %s:\n%s\n", nevra, problems);
+ goto ERROR;
+ }
// Initialize the build environment
r = pakfire_build_init(build);
// Install the source package
r = pakfire_build_install_source_package(build, package);
if (r) {
- ERROR(build->pakfire, "Could not install the source package: %m\n");
+ BUILD_ERROR(build, "Could not install the source package: %m\n");
goto ERROR;
}
// Mount the ccache
r = pakfire_build_mount_ccache(build);
if (r) {
- ERROR(build->pakfire, "Could not mount the ccache: %m\n");
+ BUILD_ERROR(build, "Could not mount the ccache: %m\n");
goto ERROR;
}
// Create BUILDROOT
buildroot = pakfire_mkdtemp(build->buildroot);
if (!buildroot) {
- ERROR(build->pakfire, "Could not create BUILDROOT: %m\n");
+ BUILD_ERROR(build, "Could not create BUILDROOT: %m\n");
goto ERROR;
}
// Create the packages
r = pakfire_build_packages(build, makefile);
if (r) {
- ERROR(build->pakfire, "Could not create packages: %m\n");
+ BUILD_ERROR(build, "Could not create packages: %m\n");
goto ERROR;
}
if (r)
goto ERROR;
- INFO(build->pakfire, "Build successfully completed in %s\n", duration);
+ BUILD_INFO(build, "Build successfully completed in %s\n", duration);
ERROR:
if (makefile)
pakfire_parser_unref(makefile);
if (package)
pakfire_package_unref(package);
+ if (problems)
+ free(problems);
// Cleanup buildroot
if (buildroot)
return r;
}
+static int pakfire_build_mkimage_install_deps(struct pakfire_build* build,
+ const char* type) {
+ struct pakfire_transaction* transaction = NULL;
+ char requires[NAME_MAX];
+ char* problems = NULL;
+ int r;
+
+ // Format requires
+ r = pakfire_string_format(requires, "mkimage(%s)", type);
+ if (r)
+ goto ERROR;
+
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, build->pakfire, 0);
+ if (r) {
+ ERROR(build->pakfire, "Could not create transaction: %m\n");
+ goto ERROR;
+ }
+
+ // Add requires to the request
+ r = pakfire_transaction_request(transaction,
+ PAKFIRE_JOB_INSTALL, requires, PAKFIRE_JOB_ESSENTIAL);
+ if (r) {
+ ERROR(build->pakfire, "Could not add '%s' to the transaction: %m\n", requires);
+ goto ERROR;
+ }
+
+ // Solve the request
+ r = pakfire_transaction_solve(transaction, 0, &problems);
+ if (r) {
+ ERROR(build->pakfire, "Could not solve the request:\n%s\n", problems);
+ goto ERROR;
+ }
+
+ // Run the transaction
+ r = pakfire_transaction_run(transaction);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (problems)
+ free(problems);
+
+ return r;
+}
+
+static int pakfire_build_collect_packages(struct pakfire_build* build, const char* path) {
+ struct pakfire_transaction* transaction = NULL;
+ char* problems = NULL;
+ char* p = NULL;
+ int r;
+
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, build->pakfire, 0);
+ if (r) {
+ ERROR(build->pakfire, "Could not create transaction: %m\n");
+ goto ERROR;
+ }
+
+ // XXX
+ // Install the base system
+ r = pakfire_transaction_request(transaction,
+ PAKFIRE_JOB_INSTALL, "ipfire-release", PAKFIRE_JOB_ESSENTIAL);
+ if (r) {
+ ERROR(build->pakfire, "Could not install 'ipfire-release': %m\n");
+ goto ERROR;
+ }
+
+ // Solve the transaction
+ r = pakfire_transaction_solve(transaction, 0, &problems);
+ if (r) {
+ ERROR(build->pakfire, "Could not solve request:\n%s\n", problems);
+ goto ERROR;
+ }
+
+ // Empty transaction?
+ if (!pakfire_transaction_count(transaction)) {
+ ERROR(build->pakfire, "The transaction is unexpectedly empty\n");
+ r = 1;
+ goto ERROR;
+ }
+
+ // Dump the transaction
+ p = pakfire_transaction_dump(transaction, 80);
+ if (!p) {
+ ERROR(build->pakfire, "Could not dump the transaction: %m\n");
+ r = 1;
+ goto ERROR;
+ }
+
+ // Log the dump
+ INFO(build->pakfire, "%s\n", p);
+
+ // Download all packages
+ r = pakfire_transaction_download(transaction);
+ if (r) {
+ ERROR(build->pakfire, "Could not download the transaction: %m\n");
+ goto ERROR;
+ }
+
+ // Create a repository with all packages in this transaction
+ r = pakfire_transaction_compose_repo(transaction, NULL, path);
+ if (r) {
+ ERROR(build->pakfire, "Could not create repository: %m\n");
+ goto ERROR;
+ }
+
+ // XXX Should we perform installcheck here?
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (problems)
+ free(problems);
+ if (p)
+ free(p);
+
+ return r;
+}
+
+PAKFIRE_EXPORT int pakfire_build_mkimage(struct pakfire_build* build,
+ const char* type, FILE* f) {
+ FILE* t = NULL;
+ char packagesdir[PATH_MAX];
+ char path[PATH_MAX];
+ char* p = NULL;
+ int r;
+
+ // Check inputs
+ if (!type || !f)
+ return -EINVAL;
+
+ // Create a path inside the build environment
+ r = pakfire_path(build->pakfire, path, "%s",
+ PAKFIRE_TMP_DIR "/pakfire-image.XXXXXX");
+ if (r)
+ goto ERROR;
+
+ // Allocate a temporary file
+ t = pakfire_mktemp(path, 0600);
+ if (!t) {
+ ERROR(build->pakfire, "Could not allocate a temporary file: %m\n");
+ r = 1;
+ goto ERROR;
+ }
+
+ // Create a path for all packages
+ r = pakfire_path(build->pakfire, packagesdir, "%s",
+ PAKFIRE_TMP_DIR "/pakfire-packages.XXXXXX");
+ if (r)
+ goto ERROR;
+
+ p = pakfire_mkdtemp(packagesdir);
+ if (!p)
+ goto ERROR;
+
+ // Collect all packages
+ r = pakfire_build_collect_packages(build, packagesdir);
+ if (r)
+ goto ERROR;
+
+ // Initialize the build environment
+ r = pakfire_build_init(build);
+ if (r)
+ goto ERROR;
+
+ // Install all dependencies
+ r = pakfire_build_mkimage_install_deps(build, type);
+ if (r)
+ goto ERROR;
+
+ const char* args[] = {
+ type,
+ pakfire_relpath(build->pakfire, path),
+ pakfire_relpath(build->pakfire, packagesdir),
+ NULL,
+ };
+
+ // Run the mkimage script
+ r = pakfire_build_run_script(build, "mkimage", args);
+ if (r)
+ goto ERROR;
+
+ // Copy data to its destination
+ r = pakfire_copy(build->pakfire, t, f);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (t)
+ fclose(t);
+
+ // Unlink the temporary file
+ if (*path)
+ unlink(path);
+
+ // Remove all packages
+ pakfire_rmtree(packagesdir, 0);
+
+ return r;
+}
+
int pakfire_build_clean(struct pakfire* pakfire, int flags) {
struct pakfire_repo* local = NULL;
int r = 0;
return r;
}
+static int pakfire_build_install(struct pakfire_build* build, const char** packages) {
+ struct pakfire_transaction* transaction = NULL;
+ char* problems = NULL;
+ int r;
+
+ // Create a new transaction
+ r = pakfire_transaction_create(&transaction, build->pakfire, 0);
+ if (r)
+ goto ERROR;
+
+ // Install all packages
+ for (const char** p = packages; *p; p++) {
+ r = pakfire_transaction_request(transaction, PAKFIRE_JOB_INSTALL, *p, 0);
+ if (r)
+ goto ERROR;
+ }
+
+ // Solve the transaction
+ r = pakfire_transaction_solve(transaction, 0, &problems);
+ if (r) {
+ ERROR(build->pakfire, "Could not install packages:\n%s\n", problems);
+ goto ERROR;
+ }
+
+ // Run the transaction
+ r = pakfire_transaction_run(transaction);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (problems)
+ free(problems);
+
+ return r;
+}
+
/*
This is a convenience function that sets up a build environment and
then drops the user into an interactive shell.
// Install any additional packages
if (packages) {
- r = pakfire_install(build->pakfire, 0, 0, packages, NULL, 0, NULL, NULL, NULL);
+ r = pakfire_build_install(build, packages);
if (r)
- return r;
+ goto ERROR;
}
// Run shell