#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>
};
struct pakfire_build {
+ struct pakfire_ctx* ctx;
struct pakfire* pakfire;
int nrefs;
// 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;
}
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;
+
+ 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;
+
+ 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,
struct pakfire_repo* repo, void* p) {
char path[PATH_MAX];
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;
}
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);
// 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;
}
// 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);
}
}
// 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;
}
-static int pakfire_build_log_strftime(
- char* buffer, const size_t length, const double t) {
- 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;
-
- if (h)
- return __pakfire_string_format(buffer, length, "%02d:%02d:%02d.%04d", h, m, s, ms);
-
- else if (m)
- return __pakfire_string_format(buffer, length, " %02d:%02d.%04d", m, s, ms);
-
- else
- return __pakfire_string_format(buffer, length, " %02d.%04d", s, ms);
-}
-
-static int pakfire_build_log_callback(struct pakfire* pakfire,
- void* data, int priority, const char* line, size_t length) {
- struct pakfire_build* build = data;
- char buffer[128];
- int r;
-
- // Get the runtime of the build
- const double t = pakfire_build_duration(build);
- if (t < 0)
- return t;
-
- // Format the timestamp
- r = pakfire_build_log_strftime(buffer, sizeof(buffer), t);
- if (r < 0)
- return r;
-
- // Pass the message to the upstream logger
- pakfire_log_condition(pakfire, priority, 0, "[%s] %s", buffer, line);
-
- return 0;
-}
-
/*
Sets up a new jail for this build
*/
return r;
}
- // Configure our custom logging callback
- pakfire_jail_set_log_callback(build->jail, pakfire_build_log_callback, build);
-
// Connect the jail to our cgroup
r = pakfire_jail_set_cgroup(build->jail, build->cgroup);
if (r) {
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
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;
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_transaction* transaction = (struct pakfire_transaction*)p;
// Dependency Error
case 2:
- ERROR(build->pakfire, "Install test failed:\n%s\n", problems);
+ BUILD_ERROR(build, "Install test failed:\n%s\n", problems);
break;
// Any other errors
default:
- ERROR(build->pakfire, "Install test failed: %m\n");
+ BUILD_ERROR(build, "Install test failed: %m\n");
goto ERROR;
}
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];
r = pakfire_transaction_solve(transaction, 0, &problems);
if (r) {
if (problems)
- ERROR(build->pakfire, "Could not install the source package:\n%s\n", problems);
+ BUILD_ERROR(build, "Could not install the source package:\n%s\n", problems);
goto ERROR;
}
// 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;
}
struct pakfire_package* package = NULL;
struct pakfire_parser* makefile = NULL;
char* buildroot = NULL;
+ char* problems = NULL;
char duration[TIME_STRING_MAX];
int r;
goto ERROR;
const char* nevra = pakfire_package_get_string(package, PAKFIRE_PKG_NEVRA);
+ const char* uuid = pakfire_package_get_string(package, PAKFIRE_PKG_UUID);
- INFO(build->pakfire, "Building %s...\n", nevra);
+ BUILD_INFO(build, "Building %s (%s)...\n", nevra, uuid);
// Check if this package can be build in this environment
if (!pakfire_package_supports_build_arch(package, arch)) {
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);
if (r)
// 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)
};
// Run the mkimage script
- r = pakfire_build_run_script(build, "mkimage", args, NULL, NULL, NULL);
+ r = pakfire_build_run_script(build, "mkimage", args);
if (r)
goto ERROR;
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