]> git.ipfire.org Git - pakfire.git/commitdiff
builder: Move setup of build environment into libpakfire
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 5 Jun 2021 11:59:23 +0000 (11:59 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 5 Jun 2021 11:59:23 +0000 (11:59 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/libpakfire/build.c
src/libpakfire/include/pakfire/build.h
src/libpakfire/include/pakfire/pakfire.h
src/libpakfire/pakfire.c
src/pakfire/base.py
src/pakfire/builder.py

index 8f27060d54b34944de8e8fce27b8051239201699..f1f2a76bd8a12577b1909868ecf2fa6cadd8cc45 100644 (file)
@@ -51,21 +51,37 @@ static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
 }
 
 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) {
index f09df6dd201bdede5e4320cb4b6a00bf8d42fe4e..43141ca7d01bfa3828c7206ad43a84f58e10e84d 100644 (file)
@@ -20,6 +20,7 @@
 
 #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",
@@ -52,6 +58,155 @@ static const char* stages[] = {
        "\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;
index 8fb99d3672a6244ac4160c2e9cb2233a61ee5579..90edc86d295ad248eba024ece4115ccee66fa012 100644 (file)
@@ -28,6 +28,8 @@ enum pakfire_build_flags {
        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);
index ff4451a02749a1f1c6059d106ac64b7621dd40df..59e9c29c2f81fb45ffa9896e1c2ec722b81f1087 100644 (file)
@@ -33,6 +33,9 @@
 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,
index c1d6785a22e32de9b4dabdb7edc6d5345c9ed950..ec7d272e99ed3b4b612316f9956ccc64741c855a 100644 (file)
@@ -859,7 +859,6 @@ PAKFIRE_EXPORT int pakfire_create(Pakfire* pakfire, const char* path, const char
        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()) {
@@ -934,6 +933,13 @@ PAKFIRE_EXPORT int pakfire_create(Pakfire* pakfire, const char* path, const char
        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;
index 0bc6ba55e4582d29959be8ce259356717a9b5f4c..3486d7af78060cb99cc8452c40db4d039ffe48f7 100644 (file)
@@ -36,8 +36,8 @@ from .i18n import _
 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()
index 6c39d9824dfe450dbebbe007bf376ca1af6892a5..3164b16a93abcf5aa9176d0a0e07644f2c4fe86e 100644 (file)
@@ -99,11 +99,11 @@ class Builder(object):
                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"):
@@ -144,29 +144,6 @@ class BuilderContext(object):
                # 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:
@@ -193,9 +170,6 @@ class BuilderContext(object):
                        return ret
 
        def build(self, path, shell=True):
-               # Setup the environment
-               self._setup()
-
                # Install the package
                self._install([path])
 
@@ -203,9 +177,6 @@ class BuilderContext(object):
                        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