}
static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
- char* kwlist[] = { "path", "arch", "offline", "conf", NULL };
+ char* kwlist[] = { "path", "arch", "offline", "conf", "build",
+ "enable_ccache", "enable_snapshot", NULL };
const char* path = NULL;
const char* arch = NULL;
const char* conf = NULL;
int offline = 0;
- int flags = 0;
+ int build = 0;
+ int enable_ccache = 1;
+ int enable_snapshot = 1;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzpz", kwlist,
- &path, &arch, &offline, &conf))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzpzppp", kwlist,
+ &path, &arch, &offline, &conf, &build, &enable_ccache, &enable_snapshot))
return -1;
+ int flags = 0;
+
// Enable offline mode
if (offline)
flags |= PAKFIRE_FLAGS_OFFLINE;
+ // Enable build mode
+ if (build) {
+ flags |= PAKFIRE_FLAGS_BUILD;
+
+ if (!enable_ccache)
+ flags |= PAKFIRE_FLAGS_DISABLE_CCACHE;
+
+ if (!enable_snapshot)
+ flags |= PAKFIRE_FLAGS_DISABLE_SNAPSHOT;
+ }
+
// Create a new Pakfire instance
int r = pakfire_create(&self->pakfire, path, arch, conf, flags);
if (r) {
#include <errno.h>
#include <stdlib.h>
+#include <sys/mount.h>
#include <pakfire/build.h>
#include <pakfire/execute.h>
#include <pakfire/packager.h>
#include <pakfire/parser.h>
#include <pakfire/private.h>
+#include <pakfire/request.h>
#include <pakfire/scriptlet.h>
+#include <pakfire/snapshot.h>
+#include <pakfire/transaction.h>
#include <pakfire/types.h>
#include <pakfire/util.h>
+#define CCACHE_DIR "/var/cache/ccache"
+
static const char* stages[] = {
"prepare",
"build",
"\n" \
"exit 0\n"
+static int pakfire_build_install_packages(Pakfire pakfire, int* snapshot_needs_update) {
+ struct pakfire_request* request = NULL;
+ struct pakfire_transaction* transaction = NULL;
+ char** packages = NULL;
+ int r = 1;
+
+ struct pakfire_config* config = pakfire_get_config(pakfire);
+
+ // Fetch build environment
+ const char* requires = pakfire_config_get(config, "build", "requires", NULL);
+ if (!requires) {
+ ERROR(pakfire, "No build requirements have been defined\n");
+ goto ERROR;
+ }
+
+ // Split requirements into packages
+ packages = pakfire_split_string(requires, ',');
+ if (!packages)
+ goto ERROR;
+
+ // Create a new request
+ r = pakfire_request_create(&request, pakfire, 0);
+ if (r)
+ goto ERROR;
+
+ // Install all packages
+ for (char** package = packages; *package; package++) {
+ r = pakfire_request_install(request, *package);
+ if (r) {
+ ERROR(pakfire, "Cannot install '%s': %m\n", *package);
+ goto ERROR;
+ }
+ }
+
+ // XXX update everything
+
+ // Solve the request
+ r = pakfire_request_solve(request, 0);
+ if (r)
+ goto ERROR;
+
+ // Fetch the transaction
+ transaction = pakfire_request_get_transaction(request);
+ if (!transaction)
+ goto ERROR;
+
+ // Mark the snapshot for update
+ if (pakfire_transaction_count(transaction))
+ *snapshot_needs_update = 1;
+
+ // Download
+ r = pakfire_transaction_download(transaction);
+ if (r)
+ goto ERROR;
+
+ // Run the transaction
+ r = pakfire_transaction_run(transaction);
+ if (r)
+ goto ERROR;
+
+ // Success
+ r = 0;
+
+ERROR:
+ if (transaction)
+ pakfire_transaction_unref(transaction);
+ if (request)
+ pakfire_request_unref(request);
+ if (packages) {
+ for (char** package = packages; *package; package++)
+ free(*package);
+ free(packages);
+ }
+ if (config)
+ pakfire_config_unref(config);
+
+ return r;
+}
+
+int pakfire_build_setup(Pakfire pakfire) {
+ char path[PATH_MAX];
+ int r;
+
+ // Mount ccache
+ if (!pakfire_has_flag(pakfire, PAKFIRE_FLAGS_DISABLE_CCACHE)) {
+ r = pakfire_make_cache_path(pakfire, path, "%s", "ccache");
+ if (r < 0)
+ return r;
+
+ // Ensure path exists
+ r = pakfire_mkdir(path, 0);
+ if (r && errno != EEXIST) {
+ ERROR(pakfire, "Could not create ccache directory %s: %m\n", path);
+ return r;
+ }
+
+ r = pakfire_bind(pakfire, path, CCACHE_DIR, MS_NOSUID|MS_NOEXEC|MS_NODEV);
+ if (r) {
+ ERROR(pakfire, "Could not mount ccache: %m\n");
+ return r;
+ }
+ }
+
+ // Extract snapshot
+ if (!pakfire_has_flag(pakfire, PAKFIRE_FLAGS_DISABLE_SNAPSHOT)) {
+ r = pakfire_make_cache_path(pakfire, path, "%s", "snapshot.tar.zst");
+ if (r < 0)
+ return r;
+
+ // Open the snapshot
+ FILE* f = fopen(path, "r");
+
+ // Try restoring the snapshot
+ if (f) {
+ r = pakfire_snapshot_restore(pakfire, f);
+ if (r) {
+ fclose(f);
+ return r;
+ }
+ }
+
+ // Tells us whether we need to (re-)create the snapshot
+ int snapshot_needs_update = 0;
+
+ // Install or update any build dependencies
+ r = pakfire_build_install_packages(pakfire, &snapshot_needs_update);
+ if (r)
+ return r;
+
+ if (snapshot_needs_update) {
+ // Open snapshot file for writing
+ f = fopen(path, "w");
+ if (!f) {
+ ERROR(pakfire, "Could not open snapshot file for writing: %m\n");
+ return 1;
+ }
+
+ // Create a new snapshot
+ r = pakfire_snapshot_create(pakfire, f);
+ fclose(f);
+
+ if (r)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
static int pakfire_build_run_script(Pakfire pakfire, const char* filename, const char* args[],
pakfire_execute_logging_callback logging_callback, void* data) {
char* script = NULL;
PAKFIRE_BUILD_INTERACTIVE = (1 << 0),
};
+int pakfire_build_setup(Pakfire pakfire);
+
int pakfire_build(Pakfire pakfire, const char* path, const char* target, int flags,
pakfire_execute_logging_callback logging_callback, void* data);
int pakfire_shell(Pakfire pakfire);
enum pakfire_flags {
PAKFIRE_FLAGS_OFFLINE = (1 << 0),
PAKFIRE_FLAGS_NON_INTERACTIVE = (1 << 1),
+ PAKFIRE_FLAGS_BUILD = (1 << 2),
+ PAKFIRE_FLAGS_DISABLE_CCACHE = (1 << 3),
+ PAKFIRE_FLAGS_DISABLE_SNAPSHOT = (1 << 4),
};
int pakfire_create(Pakfire* pakfire, const char* path, const char* arch,
DEBUG(p, " arch = %s\n", pakfire_get_arch(p));
DEBUG(p, " path = %s\n", pakfire_get_path(p));
-
// Automatically disable interactive mode
if (!pakfire_has_flag(p, PAKFIRE_FLAGS_NON_INTERACTIVE)) {
if (pakfire_tty_is_noninteractive()) {
if (r)
goto ERROR;
+ // Setup build stuff
+ if (pakfire_has_flag(p, PAKFIRE_FLAGS_BUILD)) {
+ r = pakfire_build_setup(p);
+ if (r)
+ goto ERROR;
+ }
+
*pakfire = p;
return 0;
class Pakfire(_pakfire.Pakfire):
__version__ = PAKFIRE_VERSION
- def __init__(self, path=None, arch=None, conf=None, offline=False):
- _pakfire.Pakfire.__init__(self, path, arch, conf=conf, offline=offline)
+ def __init__(self, path=None, arch=None, conf=None, offline=False, **kwargs):
+ _pakfire.Pakfire.__init__(self, path, arch, conf=conf, offline=offline, **kwargs)
# Initialise logging system
self.log = self._setup_logger()
pakfire = base.Pakfire(
arch=self.arch,
conf=self.conf,
- )
- # Mount ccache
- if self.settings.get("enable_ccache"):
- pakfire.bind(CCACHE_CACHE_DIR, "/var/cache/ccache")
+ # Enable build mode
+ build=True,
+ **self.settings,
+ )
# Setup domain name resolution in chroot
for i in ("/etc/resolv.conf", "/etc/hosts"):
# Get a reference to the logger
self.log = self.builder.log
- def _setup(self):
- """
- Sets up the environment by installing some basic packages
- """
- enable_snapshot = self.builder.settings.get("enable_snapshot", True)
-
- snapshot_path = self.pakfire.make_cache_path("snapshot.tar.zst")
-
- # Restore the snapshot if available
- if enable_snapshot:
- try:
- self.pakfire.restore_snapshot(snapshot_path)
-
- # Ignore if no snapshot was present
- except FileNotFoundError:
- pass
-
- # Install any updates and essential packages
- # If there have been updates, or on a fresh install, re-create the snapshot
- if self._install(BUILD_PACKAGES):
- if enable_snapshot:
- self.pakfire.create_snapshot(snapshot_path)
-
def _install(self, packages):
self.log.debug(_("Installing packages in build environment:"))
for package in packages:
return ret
def build(self, path, shell=True):
- # Setup the environment
- self._setup()
-
# Install the package
self._install([path])
self.pakfire.build(makefile, logging_callback=self.log.log, interactive=shell)
def shell(self, packages=[], install=None):
- # Setup the environment
- self._setup()
-
if install:
packages += install