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 \
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 \
#include <Python.h>
#include <errno.h>
+#include <pakfire/build.h>
#include <pakfire/constants.h>
#include <pakfire/dist.h>
#include <pakfire/execute.h>
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",
METH_VARARGS,
NULL,
},
+ {
+ "build",
+ (PyCFunction)Pakfire_build,
+ METH_VARARGS|METH_KEYWORDS,
+ NULL
+ },
{
"create_snapshot",
(PyCFunction)Pakfire_create_snapshot,
METH_VARARGS,
NULL
},
+ {
+ "shell",
+ (PyCFunction)Pakfire_shell,
+ METH_NOARGS,
+ NULL,
+ },
{
"restore_snapshot",
(PyCFunction)Pakfire_restore_snapshot,
--- /dev/null
+/*#############################################################################
+# #
+# 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);
+}
--- /dev/null
+/*#############################################################################
+# #
+# 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 */
pakfire_archive_signature_ref;
pakfire_archive_signature_unref;
+ # build
+ pakfire_build;
+ pakfire_shell;
+
# db
pakfire_db_add_package;
pakfire_db_check;
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
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()