]> git.ipfire.org Git - people/ms/pakfire.git/commitdiff
packager: Package scriptlets
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 3 Jun 2021 17:54:27 +0000 (17:54 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 3 Jun 2021 17:54:27 +0000 (17:54 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c
src/libpakfire/build.c
src/libpakfire/db.c
src/libpakfire/include/pakfire/packager.h
src/libpakfire/packager.c
src/scripts/find-prerequires

index 879c12d37bf0badcf0901b0cf3e53ace0c1568d7..c0777e300b2e372ed1963660b149eb16ebe8d95b 100644 (file)
@@ -1673,7 +1673,7 @@ struct pakfire_scriptlet* pakfire_archive_get_scriptlet(
                const char* t = pakfire_scriptlet_get_type(scriptlet);
 
                if (strcmp(t, type) == 0)
-                       return scriptlet;
+                       return pakfire_scriptlet_ref(scriptlet);
        }
 
        return NULL;
index 8e8adc53ca9388259036c819df12e13a5b06ac9e..c2ba2b325e18926bc7b3c77986ecff48ba0a3279 100644 (file)
@@ -30,6 +30,7 @@
 #include <pakfire/packager.h>
 #include <pakfire/parser.h>
 #include <pakfire/private.h>
+#include <pakfire/scriptlet.h>
 #include <pakfire/types.h>
 #include <pakfire/util.h>
 
@@ -309,6 +310,140 @@ ERROR:
        return r;
 }
 
+static int pakfire_build_add_scriptlet_requires(Pakfire pakfire, PakfirePackage pkg,
+               struct pakfire_scriptlet* scriptlet) {
+       char** prerequires = NULL;
+       char path[PATH_MAX];
+       size_t size;
+       int r;
+
+       const char* root = pakfire_get_path(pakfire);
+
+       // Make filename
+       r = pakfire_make_path(pakfire, path, "tmp/.pakfire-scriptlet.XXXXXX");
+       if (r < 0)
+               return r;
+
+       // Fetch scriptlet payload
+       const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
+
+       // Create a temporary file
+       FILE* f = pakfire_mktemp(path);
+       if (!f)
+               return 1;
+
+       // Write scriptlet
+       ssize_t bytes_written = fwrite(data, 1, size, f);
+       if (bytes_written < 0) {
+               ERROR(pakfire, "Could not write to %s: %m\n", path);
+               fclose(f);
+               goto ERROR;
+       }
+
+       // Close file
+       fclose(f);
+
+       // Build commandline
+       const char* args[] = {
+               pakfire_path_relpath(root, path),
+               NULL,
+       };
+
+       // Find all pre-requires
+       r = pakfire_build_run_script(pakfire, "find-prerequires", args,
+               pakfire_execute_capture_stdout_to_array, &prerequires);
+       if (r)
+               goto ERROR;
+
+       // Add all pre-requires to the package
+       if (prerequires) {
+               for (char** element = prerequires; *element; element++) {
+                       DEBUG(pakfire, "Adding pre-requires: %s\n", *element);
+                       pakfire_package_add_prerequires(pkg, *element);
+               }
+       }
+
+ERROR:
+       if (r && *path)
+               unlink(path);
+       if (prerequires) {
+               for (char** element = prerequires; *element; element++)
+                       free(*element);
+               free(prerequires);
+       }
+       return r;
+}
+
+static int pakfire_build_package_add_scriptlet(Pakfire pakfire, PakfirePackage pkg,
+               struct pakfire_packager* packager, const char* type, const char* data) {
+       struct pakfire_scriptlet* scriptlet = NULL;
+       char* shell = NULL;
+       int r;
+
+       // Wrap scriptlet into a shell script
+       r = asprintf(&shell, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data);
+       if (r < 0)
+               goto ERROR;
+
+       // Create a scriptlet
+       r = pakfire_scriptlet_create(&scriptlet, pakfire, type, shell, 0);
+       if (r)
+               goto ERROR;
+
+       // Add it to the package
+       r = pakfire_packager_add_scriptlet(packager, scriptlet);
+       if (r) {
+               ERROR(pakfire, "Could not add scriptlet %s\n", type);
+               goto ERROR;
+       }
+
+       // Add scriptlet requirements
+       r = pakfire_build_add_scriptlet_requires(pakfire, pkg, scriptlet);
+       if (r) {
+               ERROR(pakfire, "Could not add scriptlet requirements: %s\n", strerror(errno));
+               goto ERROR;
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (scriptlet)
+               pakfire_scriptlet_unref(scriptlet);
+       if (shell)
+               free(shell);
+
+       return r;
+}
+
+static int pakfire_build_package_add_scriptlets(Pakfire pakfire, PakfireParser makefile,
+               const char* namespace, PakfirePackage pkg, struct pakfire_packager* packager) {
+       char name[NAME_MAX];
+       int r;
+
+       for (const char** type = pakfire_scriptlet_types; *type; type++) {
+               r = pakfire_string_format(name, "scriptlet:%s", *type);
+               if (r < 0)
+                       return r;
+
+               // Fetch the scriptlet
+               char* data = pakfire_parser_get(makefile, namespace, name);
+               if (!data)
+                       continue;
+
+               // Add it to the package
+               r = pakfire_build_package_add_scriptlet(pakfire, pkg, packager, *type, data);
+               if (r) {
+                       free(data);
+                       return r;
+               }
+
+               free(data);
+       }
+
+       return 0;
+}
+
 static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile,
                const char* buildroot, const char* namespace, const char* target) {
        PakfireRepo repo = NULL;
@@ -354,6 +489,11 @@ static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile,
        if (r)
                goto ERROR;
 
+       // Add scriptlets
+       r = pakfire_build_package_add_scriptlets(pakfire, makefile, namespace, pkg, packager);
+       if (r)
+               goto ERROR;
+
        // Write the finished package
        r = pakfire_packager_finish_to_directory(packager, target);
        if (r) {
index 5a64f3f39aca218244c375d399e5304c349e6417..67536842ed643b01b808446e121bd72fbb6e184f 100644 (file)
@@ -936,7 +936,7 @@ static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, Pa
 
        for (const char** type = pakfire_scriptlet_types; *type; type++) {
                // Fetch the scriptlet
-                       struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type);
+               struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type);
                if (!scriptlet)
                        continue;
 
index 811f3ee8f3336292f67d72d5a47aeb52684e2625..eabe7e1a9411b430c766667cb2c6b2be639adc65 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef PAKFIRE_PACKAGER_H
 #define PAKFIRE_PACKAGER_H
 
+#include <pakfire/scriptlet.h>
 #include <pakfire/types.h>
 
 struct pakfire_packager;
@@ -39,4 +40,7 @@ int pakfire_packager_finish_to_directory(struct pakfire_packager* packager,
 int pakfire_packager_add(struct pakfire_packager* packager,
        const char* sourcepath, const char* path);
 
+int pakfire_packager_add_scriptlet(struct pakfire_packager* packager,
+       struct pakfire_scriptlet* scriptlet);
+
 #endif /* PAKFIRE_PACKAGER_H */
index 1850dead0c2a991af06cf62ad97e1bed4f7361ba..d25c496b9d4bcea79ac53511ed5d093a6a88266f 100644 (file)
@@ -60,6 +60,9 @@ struct pakfire_packager {
        struct archive* mtree;
        FILE* fmtree;
        size_t installsize;
+
+       struct pakfire_scriptlet** scriptlets;
+       unsigned int num_scriptlets;
 };
 
 static int pakfire_packager_create_mtree(Pakfire pakfire, struct archive** mtree,
@@ -222,6 +225,13 @@ static int pakfire_packager_create_payload(struct pakfire_packager* p) {
 }
 
 static void pakfire_packager_free(struct pakfire_packager* packager) {
+       // Scriptlets
+       if (packager->scriptlets) {
+               for (unsigned int i = 0; i < packager->num_scriptlets; i++)
+                       free(packager->scriptlets[i]);
+               free(packager->scriptlets);
+       }
+
        // Payload
        if (packager->payload)
                archive_write_free(packager->payload);
@@ -719,6 +729,29 @@ ERROR:
        return r;
 }
 
+static int pakfire_packager_write_scriptlet(struct pakfire_packager* packager,
+               struct archive* a, struct archive* mtree, struct pakfire_scriptlet* scriptlet) {
+       char filename[PATH_MAX];
+       size_t size;
+       int r;
+
+       // Fetch type
+       const char* type = pakfire_scriptlet_get_type(scriptlet);
+
+       DEBUG(packager->pakfire, "Writing scriptlet '%s' to package\n", type);
+
+       // Make filename
+       r = pakfire_string_format(filename, "scriptlet/%s", type);
+       if (r < 0)
+               return r;
+
+       // Fetch scriptlet
+       const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
+
+       // Write file
+       return pakfire_packager_write_file_from_buffer(packager, a, mtree, filename, data);
+}
+
 /*
        This function is being called at the end when all data has been added to the package.
 
@@ -810,6 +843,16 @@ PAKFIRE_EXPORT int pakfire_packager_finish(struct pakfire_packager* packager, FI
                goto ERROR;
        }
 
+       // Write scriptlets
+       for (unsigned int i = 0; i < packager->num_scriptlets; i++) {
+               r = pakfire_packager_write_scriptlet(packager, a, mtree, packager->scriptlets[i]);
+               if (r) {
+                       ERROR(packager->pakfire, "Could not add scriptlet to the archive: %s\n",
+                               strerror(errno));
+                       goto ERROR;
+               }
+       }
+
        // Finish checksums
        r = archive_write_finish_entry(mtree);
        if (r) {
@@ -997,3 +1040,22 @@ ERROR:
 
        return r;
 }
+
+int pakfire_packager_add_scriptlet(struct pakfire_packager* packager,
+               struct pakfire_scriptlet* scriptlet) {
+       if (!scriptlet) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Extend array
+       packager->scriptlets = reallocarray(packager->scriptlets,
+               packager->num_scriptlets + 1, sizeof(*packager->scriptlets));
+       if (!packager->scriptlets)
+               return 1;
+
+       // Append scriptlet
+       packager->scriptlets[packager->num_scriptlets++] = pakfire_scriptlet_ref(scriptlet);
+
+       return 0;
+}
index d4b39d093711bcfcaa27a990df9cb6d55a3e57e4..de38145ff26149a4ed254109a3772a2232263514 100644 (file)
@@ -1,20 +1,56 @@
 #!/bin/bash
+###############################################################################
+#                                                                             #
+# 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/>.       #
+#                                                                             #
+###############################################################################
 
-if [ -z "${1}" ]; then
-       echo >&2 "No input file passed!"
-       exit 1
-fi
-
-prereqs=$(bash --rpm-requires < ${1} | sort | uniq | sed -e 's/^bash(//' -e 's/)$//' -e 's/^executable(//' -e 's/)$//')
-[ -z "${prereqs}" ] && exit 0
-
-for prereq in ${prereqs}; do
-       case "${prereq}" in
-               /*)
-                       echo ${prereq}
-                       ;;
-               *)
-                       which ${prereq} 2>/dev/null
-                       ;;
-       esac
-done | sort | uniq
+error() {
+       echo "${0#/}: $@" >&2
+}
+
+set -x
+
+main() {
+       local scriptlet="${1}"
+
+       if [ ! -r "${scriptlet}" ]; then
+               error "Input file is not readable"
+               return 1
+       fi
+
+       cat "${scriptlet}" >&2
+
+       # We require a shell
+       echo "/bin/sh"
+
+       local req
+       while read -r req; do
+               case "${req}" in
+                       /*)
+                               echo "${req}"
+                               ;;
+                       *)
+                               which "${req}"
+                               ;;
+               esac
+       done < <(bash --rpm-requires < "${scriptlet}" | sed -e "s/^.*(//;s/)$//" | sort -u)
+
+       return 0
+}
+
+main "$@" || exit $?