From: Michael Tremer Date: Sat, 22 May 2021 15:10:41 +0000 (+0000) Subject: build: Move build process into libpakfire X-Git-Tag: 0.9.28~1285^2~96 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1a27600753a85338fba42537dac02598a31e12fc;p=pakfire.git build: Move build process into libpakfire Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 539895511..4288def50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 3f95ed0a2..2df99d125 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -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 index 000000000..40e65a7e2 --- /dev/null +++ b/src/libpakfire/build.c @@ -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 . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 000000000..8708d43a0 --- /dev/null +++ b/src/libpakfire/include/pakfire/build.h @@ -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 . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_BUILD_H +#define PAKFIRE_BUILD_H + +#include + +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 */ diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index f962f4264..dea1a6a57 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -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; diff --git a/src/pakfire/builder.py b/src/pakfire/builder.py index a1090be04..2b90e6db0 100644 --- a/src/pakfire/builder.py +++ b/src/pakfire/builder.py @@ -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()