]> git.ipfire.org Git - pakfire.git/commitdiff
build: Move build process into libpakfire
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 22 May 2021 15:10:41 +0000 (15:10 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 22 May 2021 15:10:41 +0000 (15:10 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/_pakfire/pakfire.c
src/libpakfire/build.c [new file with mode: 0644]
src/libpakfire/include/pakfire/build.h [new file with mode: 0644]
src/libpakfire/libpakfire.sym
src/pakfire/builder.py

index 539895511f8a7b50c24f63a56eaaaaa6d0aeb0bf..4288def5064852abe335f3392492e9033f98e558 100644 (file)
@@ -240,6 +240,7 @@ lib_LTLIBRARIES += \
 libpakfire_la_SOURCES = \
        src/libpakfire/arch.c \
        src/libpakfire/archive.c \
+       src/libpakfire/build.c \
        src/libpakfire/cgroup.c \
        src/libpakfire/compress.c \
        src/libpakfire/config.c \
@@ -271,6 +272,7 @@ libpakfire_la_SOURCES = \
 pkginclude_HEADERS += \
        src/libpakfire/include/pakfire/arch.h \
        src/libpakfire/include/pakfire/archive.h \
+       src/libpakfire/include/pakfire/build.h \
        src/libpakfire/include/pakfire/cgroup.h \
        src/libpakfire/include/pakfire/compress.h \
        src/libpakfire/include/pakfire/config.h \
index 3f95ed0a23ce0959346a13fea2a004f7ebe0ff0f..2df99d125b97d1bcfe8aaec8c9a55903f7f91159 100644 (file)
@@ -21,6 +21,7 @@
 #include <Python.h>
 #include <errno.h>
 
+#include <pakfire/build.h>
 #include <pakfire/constants.h>
 #include <pakfire/dist.h>
 #include <pakfire/execute.h>
@@ -821,6 +822,54 @@ static PyObject* Pakfire_make_cache_path(PakfireObject* self, PyObject* args) {
        return PyUnicode_FromString(cache_path);
 }
 
+static PyObject* execute_return_value(int r) {
+       // Raise an OS error if r < 0
+       if (r < 0) {
+               errno = -r;
+
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+
+       // Raise exception when the command failed
+       } else if (r > 0) {
+               PyObject* code = PyLong_FromLong(r);
+
+               PyErr_SetObject(PyExc_CommandExecutionError, code);
+               Py_DECREF(code);
+
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) {
+       char* kwlist[] = {"path", "interactive", NULL};
+
+       const char* path = NULL;
+       int interactive = 0;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|p", kwlist, &path, &interactive))
+               return NULL;
+
+       int flags = 0;
+
+       // Enable interactive mode
+       if (interactive)
+               flags |= PAKFIRE_BUILD_INTERACTIVE;
+
+       // Run build
+       int r = pakfire_build(self->pakfire, path, NULL, flags);
+
+       return execute_return_value(r);
+}
+
+static PyObject* Pakfire_shell(PakfireObject* self) {
+       int r = pakfire_shell(self->pakfire);
+
+       return execute_return_value(r);
+}
+
 static struct PyMethodDef Pakfire_methods[] = {
        {
                "bind",
@@ -828,6 +877,12 @@ static struct PyMethodDef Pakfire_methods[] = {
                METH_VARARGS,
                NULL,
        },
+       {
+               "build",
+               (PyCFunction)Pakfire_build,
+               METH_VARARGS|METH_KEYWORDS,
+               NULL
+       },
        {
                "create_snapshot",
                (PyCFunction)Pakfire_create_snapshot,
@@ -906,6 +961,12 @@ static struct PyMethodDef Pakfire_methods[] = {
                METH_VARARGS,
                NULL
        },
+       {
+               "shell",
+               (PyCFunction)Pakfire_shell,
+               METH_NOARGS,
+               NULL,
+       },
        {
                "restore_snapshot",
                (PyCFunction)Pakfire_restore_snapshot,
diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c
new file mode 100644 (file)
index 0000000..40e65a7
--- /dev/null
@@ -0,0 +1,131 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2021 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pakfire/build.h>
+#include <pakfire/execute.h>
+#include <pakfire/dist.h>
+#include <pakfire/logging.h>
+#include <pakfire/parser.h>
+#include <pakfire/private.h>
+#include <pakfire/types.h>
+#include <pakfire/util.h>
+
+static const char* stages[] = {
+       "prepare",
+       "build",
+       "test",
+       "install",
+       NULL,
+};
+
+#define TEMPLATE \
+       "#!/bin/bash --login\n" \
+       "\n" \
+       "set -e\n" \
+       "set -x\n" \
+       "\n" \
+       "%%{_%s}\n" \
+       "\n" \
+       "exit 0\n"
+
+static int pakfire_build_stage(Pakfire pakfire, PakfireParser makefile, const char* stage) {
+       char template[1024];
+
+       // Prepare template for this stage
+       int r = pakfire_string_format(template, TEMPLATE, stage);
+       if (r < 0)
+               return r;
+
+       // Create the build script
+       char* script = pakfire_parser_expand(makefile, "build", template);
+       if (!script) {
+               ERROR(pakfire, "Could not generate the build script for stage '%s': %s\n",
+                       stage, strerror(errno));
+               goto ERROR;
+       }
+
+       INFO(pakfire, "Running build stage '%s'\n", stage);
+
+       r = pakfire_execute_script(pakfire, script, strlen(script), NULL, 0, NULL, NULL);
+       if (r) {
+               ERROR(pakfire, "Build stage '%s' failed with status %d\n", stage, r);
+       }
+
+ERROR:
+       if (script)
+               free(script);
+
+       return r;
+}
+
+PAKFIRE_EXPORT int pakfire_build(Pakfire pakfire, const char* path,
+               const char* target, int flags) {
+       PakfireParser makefile = NULL;
+       struct pakfire_parser_error* error = NULL;
+
+       // Read makefile
+       int r = pakfire_read_makefile(&makefile, pakfire, path, &error);
+       if (r) {
+               if (error) {
+                       ERROR(pakfire, "Could not parse makefile %s: %s\n", path,
+                               pakfire_parser_error_get_message(error));
+                       pakfire_parser_error_unref(error);
+               } else {
+                       ERROR(pakfire, "Could not parse makefile %s: %s\n", path,
+                               strerror(errno));
+               }
+
+               goto ERROR;
+       }
+
+       // Run through all build stages
+       for (const char** stage = stages; *stage; stage++) {
+               int r = pakfire_build_stage(pakfire, makefile, *stage);
+               if (r) {
+                       // Drop to a shell for debugging
+                       if (flags & PAKFIRE_BUILD_INTERACTIVE)
+                               pakfire_shell(pakfire);
+
+                       goto ERROR;
+               }
+       }
+
+       // XXX Create the packages
+
+ERROR:
+       if (makefile)
+               pakfire_parser_unref(makefile);
+
+       return r;
+}
+
+PAKFIRE_EXPORT int pakfire_shell(Pakfire pakfire) {
+       const char* argv[] = {
+               "/bin/bash", "--login", NULL,
+       };
+
+       const int flags =
+               PAKFIRE_EXECUTE_INTERACTIVE | PAKFIRE_EXECUTE_ENABLE_NETWORK;
+
+       return pakfire_execute(pakfire, argv, NULL, flags, NULL, NULL);
+}
diff --git a/src/libpakfire/include/pakfire/build.h b/src/libpakfire/include/pakfire/build.h
new file mode 100644 (file)
index 0000000..8708d43
--- /dev/null
@@ -0,0 +1,33 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2021 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_BUILD_H
+#define PAKFIRE_BUILD_H
+
+#include <pakfire/types.h>
+
+enum pakfire_build_flags {
+       PAKFIRE_BUILD_INTERACTIVE = (1 << 0),
+};
+
+int pakfire_build(Pakfire pakfire, const char* path, const char* target, int flags);
+int pakfire_shell(Pakfire pakfire);
+
+#endif /* PAKFIRE_BUILD_H */
index f962f4264582052befa08be1874cf1efee0fc06a..dea1a6a57832ceca006f0339c20fd58405bc2a24 100644 (file)
@@ -75,6 +75,10 @@ global:
        pakfire_archive_signature_ref;
        pakfire_archive_signature_unref;
 
+       # build
+       pakfire_build;
+       pakfire_shell;
+
        # db
        pakfire_db_add_package;
        pakfire_db_check;
index a1090be04ed5eee7c64e6e8e252d3c339bfa0310..2b90e6db0c05d626acc411fb7e37318428d8a548 100644 (file)
@@ -200,31 +200,7 @@ class BuilderContext(object):
                self._install([path])
 
                for makefile in glob.glob("%s/usr/src/packages/*/*.nm" % self.pakfire.path):
-                       # Parse the makefile
-                       makefile = self.pakfire.read_makefile(makefile)
-
-                       # Execute stages
-                       for stage in ("prepare", "build", "test", "install"):
-                               # Fetch build script
-                               script = makefile.expand("build", BUILD_SCRIPT % stage)
-                               if not script:
-                                       continue
-
-                               self.log.debug("Running stage '%s'" % stage)
-
-                               # Run it
-                               try:
-                                       self.pakfire.execute_script(script, logging_callback=self.log.log,
-                                               enable_network=False, interactive=False)
-
-                               # Handle if the build script failed
-                               except CommandExecutionError as e:
-                                       # Drop into a shell if requested
-                                       if shell:
-                                               self._shell()
-
-                                       # Raise otherwise
-                                       raise e
+                       self.pakfire.build(makefile, interactive=shell)
 
        def shell(self, packages=[], install=None):
                # Setup the environment
@@ -236,15 +212,5 @@ class BuilderContext(object):
                self._install(packages)
 
                # Enter the shell
-               self._shell()
-
-       def _shell(self):
-               """
-                       Opens an interactive shell in the build environment
-               """
-               return self.pakfire.execute(
-                       ["/usr/bin/bash", "--login"],
-                       interactive=True,
-                       enable_network=True,
-               )
+               self.pakfire.shell()