1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2021 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
23 #include <sys/mount.h>
26 #include <uuid/uuid.h>
28 #define PCRE2_CODE_UNIT_WIDTH 8
31 #include <pakfire/build.h>
32 #include <pakfire/cgroup.h>
33 #include <pakfire/dependencies.h>
34 #include <pakfire/dist.h>
35 #include <pakfire/file.h>
36 #include <pakfire/i18n.h>
37 #include <pakfire/jail.h>
38 #include <pakfire/logging.h>
39 #include <pakfire/mount.h>
40 #include <pakfire/package.h>
41 #include <pakfire/packager.h>
42 #include <pakfire/parser.h>
43 #include <pakfire/private.h>
44 #include <pakfire/problem.h>
45 #include <pakfire/repo.h>
46 #include <pakfire/request.h>
47 #include <pakfire/scriptlet.h>
48 #include <pakfire/snapshot.h>
49 #include <pakfire/solution.h>
50 #include <pakfire/string.h>
51 #include <pakfire/util.h>
53 #define CCACHE_DIR "/var/cache/ccache"
55 // We guarantee 2 GiB of memory to every build container
56 #define PAKFIRE_BUILD_MEMORY_GUARANTEED (size_t)2 * 1024 * 1024 * 1024
58 // We allow only up to 2048 processes/threads for every build container
59 #define PAKFIRE_BUILD_PID_LIMIT (size_t)2048
61 // A list of packages that is installed by default
62 static const char* PAKFIRE_BUILD_PACKAGES
[] = {
67 struct pakfire_build
{
68 struct pakfire
* pakfire
;
76 char _id
[UUID_STR_LEN
];
78 char target
[PATH_MAX
];
84 struct pakfire_cgroup
* cgroup
;
87 struct pakfire_jail
* jail
;
89 // The build repository
90 struct pakfire_repo
* repo
;
92 // A list of all built packages
93 struct pakfire_packagelist
* packages
;
96 char buildroot
[PATH_MAX
];
99 char ccache_path
[PATH_MAX
];
106 "#!/bin/bash --login\n" \
115 static int pakfire_build_has_flag(struct pakfire_build
* build
, int flag
) {
116 return build
->flags
& flag
;
119 static time_t pakfire_build_duration(struct pakfire_build
* build
) {
120 // What time is it now?
121 time_t now
= time(NULL
);
127 return now
- build
->time_start
;
130 static int __pakfire_build_setup_repo(struct pakfire
* pakfire
,
131 struct pakfire_repo
* repo
, void* p
) {
136 struct pakfire_build
* build
= (struct pakfire_build
*)p
;
138 // Skip processing the installed repository
139 if (pakfire_repo_is_installed_repo(repo
))
142 // Skip processing any other internal repositories
143 if (pakfire_repo_is_internal(repo
))
146 const char* name
= pakfire_repo_get_name(repo
);
148 DEBUG(pakfire
, "Exporting repository configuration for '%s'\n", name
);
150 // Make path for configuration file
151 r
= pakfire_path(build
->pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos/%s.repo", name
);
153 ERROR(pakfire
, "Could not make repository configuration path for %s: %m\n", name
);
157 // Create the parent directory
158 r
= pakfire_mkparentdir(path
, 0755);
162 // Open the repository configuration
163 f
= fopen(path
, "w");
165 ERROR(pakfire
, "Could not open %s for writing: %m\n", path
);
169 // Write repository configuration
170 r
= pakfire_repo_write_config(repo
, f
);
172 ERROR(pakfire
, "Could not write repository configuration for %s: %m\n", name
);
176 // Bind-mount any local repositories
177 if (pakfire_repo_is_local(repo
)) {
178 const char* _path
= pakfire_repo_get_path(repo
);
180 // Bind-mount the repository data read-only
181 if (pakfire_path_exists(_path
)) {
182 r
= pakfire_jail_bind(build
->jail
, _path
, _path
, MS_RDONLY
);
184 ERROR(pakfire
, "Could not bind-mount the repository at %s: %m\n", _path
);
198 This function enables the local repository so that it can be accessed by
199 a pakfire instance running inside the chroot.
201 static int pakfire_build_enable_repos(struct pakfire_build
* build
) {
202 return pakfire_repo_walk(build
->pakfire
, __pakfire_build_setup_repo
, build
);
206 Drops the user into a shell
208 static int pakfire_build_shell(struct pakfire_build
* build
) {
211 // Export local repository if running in interactive mode
212 r
= pakfire_build_enable_repos(build
);
217 return pakfire_jail_shell(build
->jail
);
220 static int pakfire_build_read_script(struct pakfire_build
* build
,
221 const char* filename
, char** buffer
, size_t* length
) {
226 // Compose the source path
227 r
= pakfire_path_join(path
, PAKFIRE_SCRIPTS_DIR
, filename
);
229 ERROR(build
->pakfire
, "Could not compose path for script '%s': %m\n", filename
);
233 DEBUG(build
->pakfire
, "Reading script from %s...\n", path
);
236 f
= fopen(path
, "r");
238 ERROR(build
->pakfire
, "Could not open script %s: %m\n", path
);
242 // Read the file into a the buffer
243 r
= pakfire_read_file_into_buffer(f
, buffer
, length
);
245 ERROR(build
->pakfire
, "Could not read script: %m\n");
256 static int pakfire_build_run_script(
257 struct pakfire_build
* build
,
258 const char* filename
,
260 pakfire_jail_communicate_in communicate_in
,
261 pakfire_jail_communicate_out communicate_out
,
268 DEBUG(build
->pakfire
, "Running build script '%s'...\n", filename
);
271 r
= pakfire_build_read_script(build
, filename
, &script
, &length
);
273 ERROR(build
->pakfire
, "Could not read script %s: %m\n", filename
);
277 // Execute the script
278 r
= pakfire_jail_exec_script(build
->jail
, script
, length
, args
,
279 communicate_in
, communicate_out
, data
);
281 ERROR(build
->pakfire
, "Script '%s' failed with status %d\n", filename
, r
);
290 struct pakfire_find_deps_ctx
{
291 struct pakfire_package
* pkg
;
293 struct pakfire_scriptlet
* scriptlet
;
295 const pcre2_code
* filter
;
297 struct pakfire_filelist
* filelist
;
301 static int pakfire_build_make_filter(struct pakfire_build
* build
, pcre2_code
** regex
,
302 struct pakfire_parser
* makefile
, const char* namespace, const char* filter
) {
303 char* pattern
= NULL
;
307 pattern
= pakfire_parser_get(makefile
, namespace, filter
);
309 // Nothing if to if there is no or an empty pattern
310 if (!pattern
|| !*pattern
)
313 DEBUG(build
->pakfire
, "Found filter for %s: %s\n", filter
, pattern
);
315 // Compile the regular expression
316 r
= pakfire_compile_regex(build
->pakfire
, regex
, pattern
);
327 static int pakfire_build_send_filelist(struct pakfire
* pakfire
, void* data
, int fd
) {
328 struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
329 struct pakfire_file
* file
= NULL
;
332 const size_t length
= pakfire_filelist_length(ctx
->filelist
);
334 // Check if we have reached the end of the filelist
335 if (ctx
->i
>= length
)
338 // Fetch the next file
339 file
= pakfire_filelist_get(ctx
->filelist
, ctx
->i
);
341 DEBUG(pakfire
, "Could not fetch file %d: %m\n", ctx
->i
);
346 // Fetch the path of the file
347 const char* path
= pakfire_file_get_path(file
);
349 ERROR(pakfire
, "Received a file with an empty path\n");
354 // Skip files that don't match what we are looking for
355 if (ctx
->class && !pakfire_file_matches_class(file
, ctx
->class))
358 // Write path to stdin
359 r
= dprintf(fd
, "%s\n", path
);
364 // Move on to the next file
372 pakfire_file_unref(file
);
377 static int pakfire_build_process_deps(struct pakfire
* pakfire
,
378 void* data
, int priority
, const char* buffer
, const size_t length
) {
379 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
381 pcre2_match_data
* match
= NULL
;
384 // Nothing to do for an empty buffer
385 if (!buffer
|| !*buffer
)
389 // Add every dependency that we have received
391 // Copy the dependency to the stack (and remove the trailing newline)
392 r
= pakfire_string_format(dep
, "%.*s", (int)length
- 1, buffer
);
396 DEBUG(pakfire
, "Processing dependency: %s\n", dep
);
398 // Filter out any dependencies that are provided by this package
399 if (ctx
->dep
== PAKFIRE_PKG_REQUIRES
) {
400 // If this is a file, we check if it is on the filelist
401 if (pakfire_filelist_contains(ctx
->filelist
, dep
))
404 // Otherwise check if this dependency is provided by this package
405 else if (pakfire_package_matches_dep(ctx
->pkg
, PAKFIRE_PKG_PROVIDES
, dep
))
409 // Check if this dependency should be filtered
411 match
= pcre2_match_data_create_from_pattern(ctx
->filter
, NULL
);
413 ERROR(pakfire
, "Could not allocate PCRE match data: %m\n");
418 r
= pcre2_jit_match(ctx
->filter
, (PCRE2_SPTR
)dep
, length
- 1,
422 if (r
== PCRE2_ERROR_NOMATCH
) {
429 // Fetch the error message
430 r
= pcre2_get_error_message(r
, (PCRE2_UCHAR
*)error
, sizeof(error
));
432 ERROR(pakfire
, "Could not fetch PCRE error message: %m\n");
437 ERROR(pakfire
, "Could not match the filter: %s\n", error
);
443 DEBUG(pakfire
, "Skipping dependency that has been filtered: %s\n", dep
);
450 r
= pakfire_package_add_dep(ctx
->pkg
, ctx
->dep
, buffer
);
452 ERROR(pakfire
, "Could not process dependency '%s': %m\n", buffer
);
457 // Send everything else to the default logger
459 ERROR(pakfire
, "%s\n", buffer
);
466 DEBUG(pakfire
, "Skipping dependency that is provided by the package itself: %s\n", dep
);
470 pcre2_match_data_free(match
);
476 This function is a special way to run a script.
478 It will pipe the filelist into the standard input of the called script
479 and will read any dependencies from the standard output.
481 static int pakfire_build_find_deps(struct pakfire_build
* build
,
482 struct pakfire_package
* pkg
, int dep
, const char* script
,
483 struct pakfire_filelist
* filelist
, int class, const pcre2_code
* filter
) {
484 // Construct the context
485 struct pakfire_find_deps_ctx ctx
= {
492 .filelist
= filelist
,
497 // Skip calling the script if class doesn't match
498 if (class && !pakfire_filelist_matches_class(filelist
, class)) {
499 DEBUG(build
->pakfire
, "Skipping calling %s as class does not match\n", script
);
503 // Pass the buildroot as first argument
504 const char* args
[] = {
505 pakfire_relpath(build
->pakfire
, build
->buildroot
),
510 r
= pakfire_build_run_script(build
, script
, args
,
511 pakfire_build_send_filelist
, pakfire_build_process_deps
, &ctx
);
513 ERROR(build
->pakfire
, "%s returned with error %d\n", script
, r
);
518 static int pakfire_build_find_dependencies(struct pakfire_build
* build
,
519 struct pakfire_parser
* makefile
, const char* namespace,
520 struct pakfire_package
* pkg
, struct pakfire_filelist
* filelist
) {
521 pcre2_code
* filter_provides
= NULL
;
522 pcre2_code
* filter_requires
= NULL
;
525 // Fetch the provides filter
526 r
= pakfire_build_make_filter(build
, &filter_provides
,
527 makefile
, namespace, "filter_provides");
529 ERROR(build
->pakfire
, "Provides filter is broken: %m\n");
533 // Fetch the requires filter
534 r
= pakfire_build_make_filter(build
, &filter_requires
,
535 makefile
, namespace, "filter_requires");
537 ERROR(build
->pakfire
, "Requires filter is broken: %m\n");
542 r
= pakfire_build_find_deps(build
, pkg
,
543 PAKFIRE_PKG_PROVIDES
, "find-provides", filelist
, 0, filter_provides
);
547 // Find all Perl provides
548 r
= pakfire_build_find_deps(build
, pkg
,
549 PAKFIRE_PKG_PROVIDES
, "perl.prov", filelist
, PAKFIRE_FILE_PERL
, filter_provides
);
554 r
= pakfire_build_find_deps(build
, pkg
,
555 PAKFIRE_PKG_REQUIRES
, "find-requires", filelist
, 0, filter_requires
);
559 // Find all Perl requires
560 r
= pakfire_build_find_deps(build
, pkg
,
561 PAKFIRE_PKG_REQUIRES
, "perl.req", filelist
, PAKFIRE_FILE_PERL
, filter_requires
);
567 pcre2_code_free(filter_provides
);
569 pcre2_code_free(filter_requires
);
574 static int __pakfire_build_package_mark_config_files(
575 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
576 char** configfiles
= (char**)data
;
579 // Skip anything that isn't a regular file
580 if (pakfire_file_get_type(file
) == S_IFREG
)
584 const char* path
= pakfire_file_get_path(file
);
586 // Check if any configfile entry matches against this
587 for (char** configfile
= configfiles
; *configfile
; configfile
++) {
588 if (pakfire_string_startswith(path
, *configfile
)) {
589 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
601 static int pakfire_build_package_mark_config_files(struct pakfire_build
* build
,
602 struct pakfire_filelist
* filelist
, struct pakfire_parser
* makefile
, const char* namespace) {
603 char** configfiles
= NULL
;
606 // Fetch configfiles from makefile
607 r
= pakfire_parser_get_filelist(makefile
, namespace, "configfiles", &configfiles
, NULL
);
609 // If configfiles is not set, there is nothing to do
613 r
= pakfire_filelist_walk(filelist
, __pakfire_build_package_mark_config_files
,
618 for (char** configfile
= configfiles
; *configfile
; configfile
++)
626 static int pakfire_build_package_add_files(struct pakfire_build
* build
,
627 struct pakfire_parser
* makefile
, const char* buildroot
, const char* namespace,
628 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
629 struct pakfire_filelist
* filelist
= NULL
;
630 char** includes
= NULL
;
631 char** excludes
= NULL
;
634 // Fetch filelist from makefile
635 r
= pakfire_parser_get_filelist(makefile
, namespace, "files", &includes
, &excludes
);
637 // No files to package?
638 if (!includes
&& !excludes
)
641 // Allocate a new filelist
642 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
647 r
= pakfire_filelist_scan(filelist
, build
->buildroot
,
648 (const char**)includes
, (const char**)excludes
);
652 DEBUG(build
->pakfire
, "%zu file(s) found\n", pakfire_filelist_length(filelist
));
654 // Nothing to do if the filelist is empty
655 if (pakfire_filelist_is_empty(filelist
))
659 pakfire_filelist_dump(filelist
, PAKFIRE_FILE_DUMP_FULL
);
662 r
= pakfire_build_find_dependencies(build
, makefile
, namespace, pkg
, filelist
);
664 ERROR(build
->pakfire
, "Finding dependencies failed: %m\n");
668 // Mark configuration files
669 r
= pakfire_build_package_mark_config_files(build
, filelist
, makefile
, namespace);
673 // Add all files to the package
674 r
= pakfire_packager_add_files(packager
, filelist
);
680 pakfire_filelist_unref(filelist
);
682 for (char** include
= includes
; *include
; include
++)
687 for (char** exclude
= excludes
; *exclude
; exclude
++)
695 static int pakfire_build_send_scriptlet(struct pakfire
* pakfire
, void* data
, int fd
) {
696 const struct pakfire_find_deps_ctx
* ctx
= (struct pakfire_find_deps_ctx
*)data
;
699 // Fetch the scriptlet
700 const char* p
= pakfire_scriptlet_get_data(ctx
->scriptlet
, &length
);
702 ERROR(pakfire
, "Could not fetch scriptlet: %m\n");
706 // Write it into the pipe
707 ssize_t bytes_written
= write(fd
, p
, length
);
708 if (bytes_written
< 0) {
709 ERROR(pakfire
, "Could not send scriptlet: %m\n");
716 static int pakfire_build_add_scriptlet_requires(struct pakfire_build
* build
,
717 struct pakfire_package
* pkg
, struct pakfire_scriptlet
* scriptlet
) {
720 struct pakfire_find_deps_ctx ctx
= {
722 .dep
= PAKFIRE_PKG_PREREQUIRES
,
723 .scriptlet
= scriptlet
,
726 // Find all pre-requires
727 r
= pakfire_build_run_script(build
, "find-prerequires", NULL
,
728 pakfire_build_send_scriptlet
, pakfire_build_process_deps
, &ctx
);
736 static int pakfire_build_package_add_scriptlet(struct pakfire_build
* build
,
737 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
,
738 const char* type
, const char* data
) {
739 struct pakfire_scriptlet
* scriptlet
= NULL
;
743 // Wrap scriptlet into a shell script
744 r
= asprintf(&shell
, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data
);
748 // Create a scriptlet
749 r
= pakfire_scriptlet_create(&scriptlet
, build
->pakfire
, type
, shell
, 0);
753 // Add it to the package
754 r
= pakfire_packager_add_scriptlet(packager
, scriptlet
);
756 ERROR(build
->pakfire
, "Could not add scriptlet %s\n", type
);
760 // Add scriptlet requirements
761 r
= pakfire_build_add_scriptlet_requires(build
, pkg
, scriptlet
);
763 ERROR(build
->pakfire
, "Could not add scriptlet requirements: %m\n");
772 pakfire_scriptlet_unref(scriptlet
);
779 static int pakfire_build_package_add_scriptlets(struct pakfire_build
* build
,
780 struct pakfire_parser
* makefile
, const char* namespace,
781 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
785 for (const char** type
= pakfire_scriptlet_types
; *type
; type
++) {
786 r
= pakfire_string_format(name
, "scriptlet:%s", *type
);
790 // Fetch the scriptlet
791 char* data
= pakfire_parser_get(makefile
, namespace, name
);
795 // Add it to the package
796 r
= pakfire_build_package_add_scriptlet(build
, pkg
, packager
, *type
, data
);
808 static int pakfire_build_package(struct pakfire_build
* build
, struct pakfire_parser
* makefile
,
809 const char* buildroot
, const char* namespace) {
810 struct pakfire_package
* pkg
= NULL
;
811 struct pakfire_packager
* packager
= NULL
;
815 // Expand the handle into the package name
816 char* name
= pakfire_parser_expand(makefile
, "packages", namespace);
818 ERROR(build
->pakfire
, "Could not get package name: %m\n");
822 INFO(build
->pakfire
, "Building package '%s'...\n", name
);
823 DEBUG(build
->pakfire
, " buildroot = %s\n", buildroot
);
825 // Fetch build architecture
826 const char* arch
= pakfire_get_arch(build
->pakfire
);
830 // Fetch package from makefile
831 r
= pakfire_parser_create_package(makefile
, &pkg
, NULL
, namespace, arch
);
833 ERROR(build
->pakfire
, "Could not create package from makefile: %m\n");
838 const char* distribution
= pakfire_parser_get(makefile
, NULL
, "DISTRO_NAME");
840 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_DISTRO
, distribution
);
846 pakfire_package_set_uuid(pkg
, PAKFIRE_PKG_BUILD_ID
, build
->id
);
848 // Set source package
849 const char* source_name
= pakfire_parser_get(makefile
, NULL
, "name");
851 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_NAME
, source_name
);
857 const char* source_evr
= pakfire_parser_get(makefile
, NULL
, "evr");
859 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_EVR
, source_evr
);
865 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_ARCH
, "src");
870 r
= pakfire_packager_create(&packager
, build
->pakfire
, pkg
);
875 r
= pakfire_build_package_add_files(build
, makefile
, buildroot
, namespace,
881 r
= pakfire_build_package_add_scriptlets(build
, makefile
, namespace,
886 const char* path
= pakfire_repo_get_path(build
->repo
);
888 // Write the finished package
889 r
= pakfire_packager_finish_to_directory(packager
, path
, NULL
);
891 ERROR(build
->pakfire
, "pakfire_packager_finish() failed: %m\n");
895 // Cleanup all packaged files
896 r
= pakfire_packager_cleanup(packager
);
905 pakfire_packager_unref(packager
);
907 pakfire_package_unref(pkg
);
914 static int pakfire_build_package_dump(struct pakfire
* pakfire
,
915 struct pakfire_package
* pkg
, void* p
) {
916 char* dump
= pakfire_package_dump(pkg
, PAKFIRE_PKG_DUMP_LONG
);
920 INFO(pakfire
, "%s\n", dump
);
926 static int pakfire_build_packages(struct pakfire_build
* build
,
927 struct pakfire_parser
* makefile
) {
928 DEBUG(build
->pakfire
, "Creating packages...");
931 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
933 // Fetch a list all all packages
934 char** packages
= pakfire_parser_list_namespaces(makefile
, "packages.package:*");
936 ERROR(build
->pakfire
, "Could not find any packages: %m\n");
940 unsigned int num_packages
= 0;
942 // Count how many packages we have
943 for (char** package
= packages
; *package
; package
++)
946 DEBUG(build
->pakfire
, "Found %d package(s)\n", num_packages
);
948 // Build packages in reverse order
949 for (int i
= num_packages
- 1; i
>= 0; i
--) {
950 r
= pakfire_build_package(build
, makefile
, buildroot
, packages
[i
]);
955 // Rescan the build repository to import all packages again
956 r
= pakfire_repo_scan(build
->repo
, 0);
960 // Create a new packagelist
961 r
= pakfire_packagelist_create(&build
->packages
, build
->pakfire
);
965 // Fetch all packages
966 r
= pakfire_repo_to_packagelist(build
->repo
, build
->packages
);
971 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_package_dump
, NULL
);
985 static int pakfire_build_stage(struct pakfire_build
* build
,
986 struct pakfire_parser
* makefile
, const char* stage
) {
989 // Prepare template for this stage
990 int r
= pakfire_string_format(template, TEMPLATE
, stage
);
994 // Fetch the environment
995 char** envp
= pakfire_parser_make_environ(makefile
);
997 // Create the build script
998 char* script
= pakfire_parser_expand(makefile
, "build", template);
1000 ERROR(build
->pakfire
, "Could not generate the build script for stage '%s': %m\n",
1005 INFO(build
->pakfire
, "Running build stage '%s'\n", stage
);
1007 // Import environment
1008 // XXX is this a good idea?
1009 r
= pakfire_jail_import_env(build
->jail
, (const char**)envp
);
1011 ERROR(build
->pakfire
, "Could not import environment: %m\n");
1016 r
= pakfire_jail_exec_script(build
->jail
, script
, strlen(script
), NULL
, NULL
, NULL
, NULL
);
1018 ERROR(build
->pakfire
, "Build stage '%s' failed with status %d\n", stage
, r
);
1023 for (char** e
= envp
; *e
; e
++)
1034 PAKFIRE_BUILD_CLEANUP_FILES
= (1 << 0),
1035 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
= (1 << 1),
1036 PAKFIRE_BUILD_SHOW_PROGRESS
= (1 << 2),
1040 This helper function takes a callback which is expected to add any files
1041 to the given filelist which will optionally be all removed after.
1043 static int pakfire_build_post_process_files(struct pakfire_build
* build
,
1044 struct pakfire_filelist
* filelist
, const char* description
,
1045 int (*callback
)(struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
),
1047 struct pakfire_filelist
* removees
= NULL
;
1050 // Create a filelist with objects that need to be removed
1051 r
= pakfire_filelist_create(&removees
, build
->pakfire
);
1055 // Find all files that need to be removed
1056 r
= pakfire_filelist_walk(filelist
, callback
, removees
,
1057 (flags
& PAKFIRE_BUILD_SHOW_PROGRESS
) ? PAKFIRE_FILELIST_SHOW_PROGRESS
: 0);
1061 if (!pakfire_filelist_is_empty(removees
)) {
1063 INFO(build
->pakfire
, "%s\n", description
);
1065 // Show all files which will be removed
1066 pakfire_filelist_dump(removees
, PAKFIRE_FILE_DUMP_FULL
|PAKFIRE_FILE_DUMP_ISSUES
);
1068 // Remove all files on the removee list
1069 if (flags
& PAKFIRE_BUILD_CLEANUP_FILES
) {
1070 r
= pakfire_filelist_cleanup(removees
, PAKFIRE_FILE_CLEANUP_TIDY
);
1074 // Remove all files from the filelist
1075 r
= pakfire_filelist_remove_all(filelist
, removees
);
1080 // Report an error if any files have been found
1081 if (flags
& PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
)
1087 pakfire_filelist_unref(removees
);
1092 static int __pakfire_build_remove_static_libraries(
1093 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1094 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1095 char path
[PATH_MAX
];
1098 // Find all static libraries
1099 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_STATIC_LIBRARY
)) {
1100 // Copy the filename
1101 r
= pakfire_string_set(path
, pakfire_file_get_abspath(file
));
1105 // Remove the extension
1106 r
= pakfire_path_replace_extension(path
, "so");
1110 // Only delete if there is a shared object with the same name
1111 if (pakfire_path_exists(path
))
1112 return pakfire_filelist_add(removees
, file
);
1118 static int pakfire_build_post_remove_static_libraries(
1119 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1120 return pakfire_build_post_process_files(build
, filelist
,
1121 "Removing static libaries...",
1122 __pakfire_build_remove_static_libraries
,
1123 PAKFIRE_BUILD_CLEANUP_FILES
);
1126 static int __pakfire_build_remove_libtool_archives(
1127 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1128 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1130 // Find all libtool archive files
1131 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_LIBTOOL_ARCHIVE
))
1132 return pakfire_filelist_add(removees
, file
);
1137 static int pakfire_build_post_remove_libtool_archives(
1138 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1139 return pakfire_build_post_process_files(build
, filelist
,
1140 "Removing libtool archives...",
1141 __pakfire_build_remove_libtool_archives
,
1142 PAKFIRE_BUILD_CLEANUP_FILES
);
1145 static int __pakfire_build_check_broken_symlinks(
1146 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1147 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1150 // Ignore anything that isn't a symlink
1151 switch (pakfire_file_get_type(file
)) {
1153 if (!pakfire_file_symlink_target_exists(file
)) {
1154 r
= pakfire_filelist_add(broken
, file
);
1161 // Ignore anything that isn't a symlink
1169 static int pakfire_build_post_check_broken_symlinks(
1170 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1171 return pakfire_build_post_process_files(build
, filelist
,
1172 "Broken symlinks have been found:",
1173 __pakfire_build_check_broken_symlinks
,
1174 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1180 static int pakfire_build_post_check_buildroot(
1181 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1182 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1184 // Nested function to keep a reference to buildroot
1185 int __pakfire_build_post_check_buildroot(
1186 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1187 struct pakfire_filelist
* matches
= (struct pakfire_filelist
*)data
;
1191 const char* path
= pakfire_file_get_path(file
);
1195 // Do not run this for Python bytecode files
1196 if (pakfire_path_match("**.pyc", path
))
1199 if (pakfire_file_payload_matches(file
, buildroot
, strlen(buildroot
))) {
1200 r
= pakfire_filelist_add(matches
, file
);
1208 return pakfire_build_post_process_files(
1209 build
, filelist
, "Files containing BUILDROOT:",
1210 __pakfire_build_post_check_buildroot
, PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1217 static int __pakfire_build_post_check_files(
1218 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1219 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1223 // Check file for issues
1224 r
= pakfire_file_check(file
, &issues
);
1226 ERROR(pakfire
, "%s: File Check failed: %m\n", pakfire_file_get_path(file
));
1230 // If any issues have been found, consider this file to be on the list
1232 r
= pakfire_filelist_add(broken
, file
);
1240 static int pakfire_build_post_check_files(
1241 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1242 return pakfire_build_post_process_files(
1246 __pakfire_build_post_check_files
,
1247 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
|PAKFIRE_BUILD_SHOW_PROGRESS
);
1250 static int pakfire_build_run_post_build_checks(struct pakfire_build
* build
) {
1251 struct pakfire_filelist
* filelist
= NULL
;
1254 // Create a filelist of all files in the build
1255 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1257 ERROR(build
->pakfire
, "Could not create filelist: %m\n");
1261 // Scan for all files in BUILDROOT
1262 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1266 // If the filelist is empty, we can are done
1267 if (pakfire_filelist_is_empty(filelist
)) {
1268 DEBUG(build
->pakfire
, "Empty BUILDROOT. Skipping post build checks...\n");
1273 // Remove any static libraries
1274 r
= pakfire_build_post_remove_static_libraries(build
, filelist
);
1278 // Remove any libtool archives
1279 r
= pakfire_build_post_remove_libtool_archives(build
, filelist
);
1283 // Check for any broken symlinks
1284 r
= pakfire_build_post_check_broken_symlinks(build
, filelist
);
1288 // Check for BUILDROOT
1289 r
= pakfire_build_post_check_buildroot(build
, filelist
);
1294 r
= pakfire_build_post_check_files(build
, filelist
);
1300 pakfire_filelist_unref(filelist
);
1305 static const char* post_build_scripts
[] = {
1306 "compress-man-pages",
1311 static int pakfire_build_run_post_build_scripts(struct pakfire_build
* build
) {
1313 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1315 // Set default arguments for build scripts
1316 const char* args
[] = {
1320 // Run them one by one
1321 for (const char** script
= post_build_scripts
; *script
; script
++) {
1322 int r
= pakfire_build_run_script(build
, *script
, args
, NULL
, NULL
, NULL
);
1330 static void pakfire_build_free(struct pakfire_build
* build
) {
1331 if (build
->packages
)
1332 pakfire_packagelist_unref(build
->packages
);
1335 pakfire_repo_clean(build
->repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
1336 pakfire_repo_unref(build
->repo
);
1340 pakfire_jail_unref(build
->jail
);
1342 if (build
->cgroup
) {
1343 // Destroy the cgroup
1344 pakfire_cgroup_destroy(build
->cgroup
);
1347 pakfire_cgroup_unref(build
->cgroup
);
1350 pakfire_unref(build
->pakfire
);
1354 static int pakfire_build_parse_id(struct pakfire_build
* build
, const char* id
) {
1357 // Try parsing the Build ID
1359 r
= uuid_parse(id
, build
->id
);
1361 ERROR(build
->pakfire
, "Could not parse build ID '%s'\n", id
);
1366 // Otherwise initialize the Build ID with something random
1368 uuid_generate_random(build
->id
);
1371 // Store the ID as string, too
1372 uuid_unparse_lower(build
->id
, build
->_id
);
1378 Sets up a new cgroup for this build
1380 static int pakfire_build_setup_cgroup(struct pakfire_build
* build
) {
1381 struct pakfire_config
* config
= NULL
;
1382 char path
[PATH_MAX
];
1386 r
= pakfire_string_format(path
, "pakfire/build-%s", build
->_id
);
1388 ERROR(build
->pakfire
, "Could not compose path for cgroup: %m\n");
1392 // Create a new cgroup
1393 r
= pakfire_cgroup_open(&build
->cgroup
, build
->pakfire
, path
,
1394 PAKFIRE_CGROUP_ENABLE_ACCOUNTING
);
1396 ERROR(build
->pakfire
, "Could not create cgroup for build %s: %m\n", build
->_id
);
1401 config
= pakfire_get_config(build
->pakfire
);
1405 // Guarantee some minimum memory
1406 size_t memory_guaranteed
= pakfire_config_get_bytes(config
, "build",
1407 "memory_guaranteed", PAKFIRE_BUILD_MEMORY_GUARANTEED
);
1408 if (memory_guaranteed
) {
1409 r
= pakfire_cgroup_set_guaranteed_memory(build
->cgroup
, memory_guaranteed
);
1415 size_t memory_limit
= pakfire_config_get_bytes(config
, "build", "memory_limit", 0);
1417 r
= pakfire_cgroup_set_memory_limit(build
->cgroup
, memory_limit
);
1423 size_t pid_limit
= pakfire_config_get_int(config
, "build",
1424 "pid_limit", PAKFIRE_BUILD_PID_LIMIT
);
1426 r
= pakfire_cgroup_set_pid_limit(build
->cgroup
, pid_limit
);
1433 pakfire_config_unref(config
);
1439 Sets up a new jail for this build
1441 static int pakfire_build_setup_jail(struct pakfire_build
* build
) {
1444 // Create a new jail
1445 r
= pakfire_jail_create(&build
->jail
, build
->pakfire
);
1447 ERROR(build
->pakfire
, "Could not create jail for build %s: %m\n", build
->_id
);
1451 // Connect the jail to our cgroup
1452 r
= pakfire_jail_set_cgroup(build
->jail
, build
->cgroup
);
1454 ERROR(build
->pakfire
, "Could not set cgroup for jail: %m\n");
1463 Sets up the ccache for this build
1465 static int pakfire_build_mount_ccache(struct pakfire_build
* build
) {
1468 // Do nothing if the ccache is disabled
1469 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
))
1472 // Check that the path is set
1473 if (!*build
->ccache_path
) {
1478 // Make sure the path exists
1479 r
= pakfire_mkdir(build
->ccache_path
, 0755);
1481 ERROR(build
->pakfire
, "Could not create %s: %m\n", build
->ccache_path
);
1485 // Bind-mount the directory
1486 return pakfire_jail_bind(build
->jail
, build
->ccache_path
, CCACHE_DIR
,
1487 MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
1490 static int pakfire_build_setup_ccache(struct pakfire_build
* build
) {
1493 // Check if we want a ccache
1494 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
)) {
1495 DEBUG(build
->pakfire
, "ccache usage has been disabled for this build\n");
1497 // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself
1498 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DISABLE", "1");
1500 ERROR(build
->pakfire
, "Could not disable ccache: %m\n");
1508 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DIR", CCACHE_DIR
);
1510 ERROR(build
->pakfire
, "Could not set ccache directory: %m\n");
1514 // Set CCACHE_TEMPDIR
1515 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_TEMPDIR", "/tmp");
1517 ERROR(build
->pakfire
, "Could not set ccache tempdir: %m\n");
1521 // Set a default path
1522 r
= pakfire_cache_path(build
->pakfire
, build
->ccache_path
, "%s", "ccache");
1529 static int pakfire_build_setup_repo(struct pakfire_build
* build
) {
1530 char path
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/pakfire-build-repo.XXXXXX";
1534 // Create a new repository
1535 r
= pakfire_repo_create(&build
->repo
, build
->pakfire
, PAKFIRE_REPO_RESULT
);
1537 ERROR(build
->pakfire
, "Could not create repository %s: %m", PAKFIRE_REPO_RESULT
);
1542 pakfire_repo_set_description(build
->repo
, _("Build Repository"));
1544 // Create a temporary directory
1545 const char* p
= pakfire_mkdtemp(path
);
1547 ERROR(build
->pakfire
, "Could not create a the build repository: %m\n");
1552 r
= pakfire_string_format(url
, "file://%s", path
);
1557 pakfire_repo_set_baseurl(build
->repo
, url
);
1562 static int pakfire_build_set_time_start(struct pakfire_build
* build
) {
1563 const time_t now
= time(NULL
);
1566 ERROR(build
->pakfire
, "Could not fetch start time: %m\n");
1570 build
->time_start
= now
;
1575 PAKFIRE_EXPORT
int pakfire_build_create(struct pakfire_build
** build
,
1576 struct pakfire
* pakfire
, const char* id
, int flags
) {
1579 // Allocate build object
1580 struct pakfire_build
* b
= calloc(1, sizeof(*b
));
1584 // Reference pakfire
1585 b
->pakfire
= pakfire_ref(pakfire
);
1587 // Initialize reference counter
1594 r
= pakfire_build_set_time_start(b
);
1599 r
= pakfire_build_parse_id(b
, id
);
1604 r
= pakfire_build_setup_repo(b
);
1609 r
= pakfire_build_setup_cgroup(b
);
1614 r
= pakfire_build_setup_jail(b
);
1619 r
= pakfire_build_setup_ccache(b
);
1627 pakfire_build_free(b
);
1631 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_ref(struct pakfire_build
* build
) {
1637 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_unref(struct pakfire_build
* build
) {
1638 if (--build
->nrefs
> 0)
1641 pakfire_build_free(build
);
1645 PAKFIRE_EXPORT
int pakfire_build_set_ccache_path(
1646 struct pakfire_build
* build
, const char* path
) {
1647 // Check if this can be called
1648 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
)) {
1653 // Check input value
1654 if (!path
|| !*path
) {
1660 return pakfire_string_set(build
->ccache_path
, path
);
1663 PAKFIRE_EXPORT
int pakfire_build_set_target(
1664 struct pakfire_build
* build
, const char* target
) {
1665 return pakfire_string_set(build
->target
, target
);
1668 static int pakfire_build_install_packages(struct pakfire_build
* build
,
1669 int* snapshot_needs_update
) {
1674 // Install everything
1675 r
= pakfire_install(build
->pakfire
, 0, 0, PAKFIRE_BUILD_PACKAGES
, NULL
, 0,
1676 &changed
, NULL
, NULL
);
1678 ERROR(build
->pakfire
, "Could not install build dependencies: %m\n");
1682 // Mark snapshot as changed if new packages were installed
1684 *snapshot_needs_update
= 1;
1686 // Update everything
1687 r
= pakfire_sync(build
->pakfire
, 0, 0, &changed
, NULL
, NULL
);
1689 ERROR(build
->pakfire
, "Could not update packages: %m\n");
1693 // Has anything changed?
1695 *snapshot_needs_update
= 1;
1701 Initializes the build environment
1703 static int pakfire_build_init(struct pakfire_build
* build
) {
1706 // Don't do it again
1708 DEBUG(build
->pakfire
, "Build environment has already been initialized\n");
1712 const int use_snapshot
= !pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
);
1714 // Tells us whether we need to (re-)create the snapshot
1715 int snapshot_needs_update
= 0;
1719 r
= pakfire_snapshot_restore(build
->pakfire
);
1724 // Install or update any build dependencies
1725 r
= pakfire_build_install_packages(build
, &snapshot_needs_update
);
1729 // Update the snapshot if there were changes
1730 if (use_snapshot
&& snapshot_needs_update
) {
1731 // Store the snapshot
1732 r
= pakfire_snapshot_store(build
->pakfire
);
1737 // Mark as initialized
1743 static int pakfire_build_read_makefile(struct pakfire_build
* build
,
1744 struct pakfire_parser
** parser
, struct pakfire_package
* package
) {
1745 char path
[PATH_MAX
];
1748 struct pakfire_parser_error
* error
= NULL
;
1750 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
1751 const char* name
= pakfire_package_get_string(package
, PAKFIRE_PKG_NAME
);
1753 // Compose path to makefile
1754 r
= pakfire_path(build
->pakfire
, path
, "/usr/src/packages/%s/%s.nm", nevra
, name
);
1759 r
= pakfire_read_makefile(parser
, build
->pakfire
, path
, &error
);
1762 ERROR(build
->pakfire
, "Could not parse makefile %s: %s\n", path
,
1763 pakfire_parser_error_get_message(error
));
1765 ERROR(build
->pakfire
, "Could not parse makefile %s: %m\n", path
);
1772 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1774 pakfire_parser_set(*parser
, NULL
, "BUILDROOT", buildroot
, 0);
1778 pakfire_parser_error_unref(error
);
1783 static int pakfire_build_perform(struct pakfire_build
* build
,
1784 struct pakfire_parser
* makefile
) {
1787 // Prepare the build
1788 r
= pakfire_build_stage(build
, makefile
, "prepare");
1792 // Perform the build
1793 r
= pakfire_build_stage(build
, makefile
, "build");
1798 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_TESTS
)) {
1799 r
= pakfire_build_stage(build
, makefile
, "test");
1804 // Install everything
1805 r
= pakfire_build_stage(build
, makefile
, "install");
1809 // Run post build checks
1810 r
= pakfire_build_run_post_build_checks(build
);
1812 ERROR(build
->pakfire
, "Post build checks failed\n");
1816 // Run post build scripts
1817 r
= pakfire_build_run_post_build_scripts(build
);
1825 // Drop to a shell for debugging
1826 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_INTERACTIVE
))
1827 pakfire_build_shell(build
);
1832 static int __pakfire_build_unpackaged_file(struct pakfire
* pakfire
,
1833 struct pakfire_file
* file
, void* p
) {
1834 char* s
= pakfire_file_dump(file
, PAKFIRE_FILE_DUMP_FULL
);
1836 ERROR(pakfire
, "%s\n", s
);
1843 static int pakfire_build_check_unpackaged_files(struct pakfire_build
* build
) {
1844 struct pakfire_filelist
* filelist
= NULL
;
1847 // Create a new filelist
1848 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1852 // Scan for all files in BUILDROOT
1853 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
);
1857 if (!pakfire_filelist_is_empty(filelist
)) {
1858 ERROR(build
->pakfire
, "Unpackaged files found:\n");
1860 r
= pakfire_filelist_walk(filelist
, __pakfire_build_unpackaged_file
, NULL
, 0);
1870 pakfire_filelist_unref(filelist
);
1875 static int pakfire_build_install_package(struct pakfire
* pakfire
,
1876 struct pakfire_package
* pkg
, void* p
) {
1877 struct pakfire_request
* request
= (struct pakfire_request
*)p
;
1879 return pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, pkg
,
1880 PAKFIRE_REQUEST_ESSENTIAL
);
1883 static int pakfire_build_install_test(struct pakfire_build
* build
) {
1884 struct pakfire_request
* request
= NULL
;
1885 struct pakfire_problem
* problem
= NULL
;
1886 struct pakfire_solution
* solution
= NULL
;
1887 const char* s
= NULL
;
1890 // Create a new request
1891 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
1896 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_install_package
, request
);
1898 // Solve the request
1899 r
= pakfire_request_solve(request
, 0);
1907 ERROR(build
->pakfire
, "Install test failed:\n");
1909 // Walk through all problems
1911 r
= pakfire_request_next_problem(request
, &problem
);
1915 // There are no more problems
1919 // Format the problem into something human-readable
1920 s
= pakfire_problem_to_string(problem
);
1924 ERROR(build
->pakfire
, " * %s\n", s
);
1926 // Walk through all solutions
1928 r
= pakfire_problem_next_solution(problem
, &solution
);
1932 // There are no more solutions
1936 // Format the solution into something human-readable
1937 s
= pakfire_solution_to_string(solution
);
1941 ERROR(build
->pakfire
, " * %s\n", s
);
1954 ERROR(build
->pakfire
, "Install test failed: %m\n");
1956 pakfire_request_unref(request
);
1958 pakfire_problem_unref(problem
);
1960 pakfire_solution_unref(solution
);
1965 static int pakfire_build_post_check(struct pakfire_build
* build
) {
1968 // Check for unpackaged files
1969 r
= pakfire_build_check_unpackaged_files(build
);
1973 // Perform install test
1974 r
= pakfire_build_install_test(build
);
1981 static int pakfire_build_copy_package(struct pakfire
* pakfire
,
1982 struct pakfire_package
* pkg
, void* p
) {
1983 struct pakfire_archive
* archive
= NULL
;
1984 char path
[PATH_MAX
];
1987 const char* target
= (const char*)p
;
1994 // Fetch the package filename
1995 const char* filename
= pakfire_package_get_string(pkg
, PAKFIRE_PKG_FILENAME
);
2001 // Format the destination path
2002 r
= pakfire_string_format(path
, "%s/%s", target
, filename
);
2007 archive
= pakfire_package_get_archive(pkg
);
2013 // Copy it to its destination
2014 r
= pakfire_archive_copy(archive
, path
);
2020 pakfire_archive_unref(archive
);
2025 static int pakfire_build_copy_packages(struct pakfire_build
* build
) {
2026 struct pakfire_repo
* local
= NULL
;
2029 DEBUG(build
->pakfire
, "Copying built packages\n");
2031 // Fetch local repository
2032 local
= pakfire_get_repo(build
->pakfire
, PAKFIRE_REPO_LOCAL
);
2034 // Copy all packages to the target path
2035 if (*build
->target
) {
2036 r
= pakfire_packagelist_walk(build
->packages
,
2037 pakfire_build_copy_package
, build
->target
);
2042 // If we have a local repository, we copy all packages to it
2044 const char* path
= pakfire_repo_get_path(local
);
2046 r
= pakfire_packagelist_walk(build
->packages
,
2047 pakfire_build_copy_package
, (void*)path
);
2055 pakfire_repo_unref(local
);
2060 static int pakfire_build_install_source_package(
2061 struct pakfire_build
* build
, struct pakfire_package
* package
) {
2062 struct pakfire_request
* request
= NULL
;
2063 struct pakfire_transaction
* transaction
= NULL
;
2066 // Create a new request
2067 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
2072 r
= pakfire_request_add_package(request
, PAKFIRE_REQ_INSTALL
, package
,
2073 PAKFIRE_REQUEST_ESSENTIAL
);
2077 // Install all essential packages
2078 for (const char** p
= PAKFIRE_BUILD_PACKAGES
; *p
; p
++) {
2079 r
= pakfire_request_add(request
, PAKFIRE_REQ_INSTALL
, *p
, PAKFIRE_REQUEST_ESSENTIAL
);
2084 // Solve the request
2085 r
= pakfire_request_solve(request
, 0);
2089 // Fetch the transaction
2090 r
= pakfire_request_get_transaction(request
, &transaction
);
2094 // Set how many packages have been changed
2095 const size_t changes
= pakfire_transaction_count(transaction
);
2097 // Sanity check to see if we actually try to install anything
2099 ERROR(build
->pakfire
, "The source package did not get installed\n");
2104 // Run the transaction
2105 r
= pakfire_transaction_run(transaction
, 0);
2111 pakfire_transaction_unref(transaction
);
2113 pakfire_request_unref(request
);
2118 PAKFIRE_EXPORT
int pakfire_build_exec(struct pakfire_build
* build
, const char* path
) {
2119 struct pakfire_package
* package
= NULL
;
2120 struct pakfire_parser
* makefile
= NULL
;
2121 char* buildroot
= NULL
;
2122 char duration
[TIME_STRING_MAX
];
2126 r
= pakfire_path(build
->pakfire
, build
->buildroot
, "%s",
2127 PAKFIRE_TMP_DIR
"/pakfire-buildroot.XXXXXX");
2131 // Open the source package
2132 r
= pakfire_commandline_add(build
->pakfire
, path
, &package
);
2136 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
2138 INFO(build
->pakfire
, "Building %s...\n", nevra
);
2140 // Initialize the build environment
2141 r
= pakfire_build_init(build
);
2145 // Install the source package
2146 r
= pakfire_build_install_source_package(build
, package
);
2148 ERROR(build
->pakfire
, "Could not install the source package: %m\n");
2153 r
= pakfire_build_mount_ccache(build
);
2155 ERROR(build
->pakfire
, "Could not mount the ccache: %m\n");
2160 buildroot
= pakfire_mkdtemp(build
->buildroot
);
2162 ERROR(build
->pakfire
, "Could not create BUILDROOT: %m\n");
2166 // Open the makefile
2167 r
= pakfire_build_read_makefile(build
, &makefile
, package
);
2171 // Perform the actual build
2172 r
= pakfire_build_perform(build
, makefile
);
2176 // Create the packages
2177 r
= pakfire_build_packages(build
, makefile
);
2179 ERROR(build
->pakfire
, "Could not create packages: %m\n");
2183 // Perform post build checks
2184 r
= pakfire_build_post_check(build
);
2188 // Copy packages to their destination
2189 r
= pakfire_build_copy_packages(build
);
2194 r
= pakfire_format_time(duration
, pakfire_build_duration(build
));
2198 INFO(build
->pakfire
, "Build successfully completed in %s\n", duration
);
2202 pakfire_parser_unref(makefile
);
2204 pakfire_package_unref(package
);
2206 // Cleanup buildroot
2208 pakfire_rmtree(buildroot
, 0);
2213 static int pakfire_build_mkimage_install_deps(struct pakfire_build
* build
,
2215 struct pakfire_request
* request
= NULL
;
2216 struct pakfire_transaction
* transaction
= NULL
;
2217 char requires
[NAME_MAX
];
2221 r
= pakfire_string_format(requires
, "mkimage(%s)", type
);
2225 // Create a new request
2226 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
2228 ERROR(build
->pakfire
, "Could not create request: %m\n");
2232 // Add requires to the request
2233 r
= pakfire_request_add(request
, PAKFIRE_REQ_INSTALL
, requires
,
2234 PAKFIRE_REQUEST_ESSENTIAL
);
2236 ERROR(build
->pakfire
, "Could not add '%s' to the request: %m\n", requires
);
2240 // Solve the request
2241 r
= pakfire_request_solve(request
, 0);
2243 ERROR(build
->pakfire
, "Could not solve the request\n");
2247 // Fetch the transaction
2248 r
= pakfire_request_get_transaction(request
, &transaction
);
2250 ERROR(build
->pakfire
, "Could not fetch the transaction: %m\n");
2254 // Run the transaction
2255 r
= pakfire_transaction_run(transaction
, 0);
2261 pakfire_request_unref(request
);
2263 pakfire_transaction_unref(transaction
);
2268 static int pakfire_build_collect_packages(struct pakfire_build
* build
, const char* path
) {
2269 struct pakfire_request
* request
= NULL
;
2270 struct pakfire_transaction
* transaction
= NULL
;
2274 // Create a new request
2275 r
= pakfire_request_create(&request
, build
->pakfire
, 0);
2277 ERROR(build
->pakfire
, "Could not create request: %m\n");
2282 // Install the base system
2283 r
= pakfire_request_add(request
, PAKFIRE_REQ_INSTALL
, "ipfire-release",
2284 PAKFIRE_REQUEST_ESSENTIAL
);
2286 ERROR(build
->pakfire
, "Could not install 'ipfire-release': %m\n");
2290 // Solve the request
2291 r
= pakfire_request_solve(request
, 0);
2293 ERROR(build
->pakfire
, "Could not solve request\n");
2297 // Get the transaction
2298 r
= pakfire_request_get_transaction(request
, &transaction
);
2300 ERROR(build
->pakfire
, "Could not fetch transaction: %m\n");
2304 // Empty transaction?
2305 if (!pakfire_transaction_count(transaction
)) {
2306 ERROR(build
->pakfire
, "The transaction is unexpectedly empty\n");
2311 // Dump the transaction
2312 p
= pakfire_transaction_dump(transaction
, 80);
2314 ERROR(build
->pakfire
, "Could not dump the transaction: %m\n");
2320 INFO(build
->pakfire
, "%s\n", p
);
2322 // Download all packages
2323 r
= pakfire_transaction_download(transaction
);
2325 ERROR(build
->pakfire
, "Could not download the transaction: %m\n");
2329 // Create a repository with all packages in this transaction
2330 r
= pakfire_transaction_compose_repo(transaction
, NULL
, path
);
2332 ERROR(build
->pakfire
, "Could not create repository: %m\n");
2336 // XXX Should we perform installcheck here?
2340 pakfire_transaction_unref(transaction
);
2342 pakfire_request_unref(request
);
2349 PAKFIRE_EXPORT
int pakfire_build_mkimage(struct pakfire_build
* build
,
2350 const char* type
, FILE* f
) {
2352 char packagesdir
[PATH_MAX
];
2353 char path
[PATH_MAX
];
2363 // Create a path inside the build environment
2364 r
= pakfire_path(build
->pakfire
, path
, "%s",
2365 PAKFIRE_TMP_DIR
"/pakfire-image.XXXXXX");
2369 // Allocate a temporary file
2370 t
= pakfire_mktemp(path
, 0600);
2372 ERROR(build
->pakfire
, "Could not allocate a temporary file: %m\n");
2377 // Create a path for all packages
2378 r
= pakfire_path(build
->pakfire
, packagesdir
, "%s",
2379 PAKFIRE_TMP_DIR
"/pakfire-packages.XXXXXX");
2383 p
= pakfire_mkdtemp(packagesdir
);
2387 // Collect all packages
2388 r
= pakfire_build_collect_packages(build
, packagesdir
);
2392 // Initialize the build environment
2393 r
= pakfire_build_init(build
);
2397 // Install all dependencies
2398 r
= pakfire_build_mkimage_install_deps(build
, type
);
2402 const char* args
[] = {
2404 pakfire_relpath(build
->pakfire
, path
),
2405 pakfire_relpath(build
->pakfire
, packagesdir
),
2409 // Run the mkimage script
2410 r
= pakfire_build_run_script(build
, "mkimage", args
, NULL
, NULL
, NULL
);
2414 // Copy data to its destination
2415 r
= pakfire_copy(build
->pakfire
, t
, f
);
2423 // Unlink the temporary file
2427 // Remove all packages
2428 pakfire_rmtree(packagesdir
, 0);
2433 int pakfire_build_clean(struct pakfire
* pakfire
, int flags
) {
2434 struct pakfire_repo
* local
= NULL
;
2437 // Fetch local repository
2438 local
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_LOCAL
);
2440 ERROR(pakfire
, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL
);
2444 // Destroy everything in it
2445 r
= pakfire_repo_clean(local
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
2451 pakfire_repo_unref(local
);
2457 This is a convenience function that sets up a build environment and
2458 then drops the user into an interactive shell.
2460 PAKFIRE_EXPORT
int pakfire_shell(struct pakfire
* pakfire
, const char** packages
, int flags
) {
2461 struct pakfire_build
* build
= NULL
;
2464 // Shells are always interactive
2465 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
2467 // Create a new build environment
2468 r
= pakfire_build_create(&build
, pakfire
, NULL
, flags
);
2470 ERROR(pakfire
, "Could not create build: %m\n");
2474 // Initialize the build environment
2475 r
= pakfire_build_init(build
);
2479 // Install any additional packages
2481 r
= pakfire_install(build
->pakfire
, 0, 0, packages
, NULL
, 0, NULL
, NULL
, NULL
);
2487 r
= pakfire_build_shell(build
);
2491 pakfire_build_unref(build
);