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 // Enable legacy logging
32 #define PAKFIRE_LEGACY_LOGGING
34 #include <pakfire/build.h>
35 #include <pakfire/cgroup.h>
36 #include <pakfire/config.h>
37 #include <pakfire/ctx.h>
38 #include <pakfire/dependencies.h>
39 #include <pakfire/dist.h>
40 #include <pakfire/file.h>
41 #include <pakfire/i18n.h>
42 #include <pakfire/jail.h>
43 #include <pakfire/logging.h>
44 #include <pakfire/mount.h>
45 #include <pakfire/package.h>
46 #include <pakfire/packager.h>
47 #include <pakfire/parser.h>
48 #include <pakfire/path.h>
49 #include <pakfire/private.h>
50 #include <pakfire/problem.h>
51 #include <pakfire/repo.h>
52 #include <pakfire/scriptlet.h>
53 #include <pakfire/snapshot.h>
54 #include <pakfire/solution.h>
55 #include <pakfire/string.h>
56 #include <pakfire/transaction.h>
57 #include <pakfire/util.h>
59 #define CCACHE_DIR "/var/cache/ccache"
61 // We guarantee 2 GiB of memory to every build container
62 #define PAKFIRE_BUILD_MEMORY_GUARANTEED (size_t)2 * 1024 * 1024 * 1024
64 // We allow only up to 2048 processes/threads for every build container
65 #define PAKFIRE_BUILD_PID_LIMIT (size_t)2048
67 // A list of packages that is installed by default
68 static const char* PAKFIRE_BUILD_PACKAGES
[] = {
73 struct pakfire_build
{
74 struct pakfire_ctx
* ctx
;
75 struct pakfire
* pakfire
;
83 char _id
[UUID_STR_LEN
];
85 char target
[PATH_MAX
];
88 struct timespec time_start
;
91 struct pakfire_cgroup
* cgroup
;
94 struct pakfire_jail
* jail
;
96 // The build repository
97 struct pakfire_repo
* repo
;
99 // A list of all built packages
100 struct pakfire_packagelist
* packages
;
103 char buildroot
[PATH_MAX
];
106 char ccache_path
[PATH_MAX
];
112 struct pakfire_build_callbacks
{
114 pakfire_build_log_callback log
;
120 "#!/bin/bash --login\n" \
130 Convenience macro to call the logger callback
132 static int pakfire_build_log(struct pakfire_build
* build
, int priority
, int error
,
133 const char* file
, int line
, const char* function
, const char* format
, ...) {
138 // Don't log messages of a lower loglevel
139 if (pakfire_ctx_get_log_level(build
->ctx
) < priority
)
143 va_start(args
, format
);
144 r
= vasprintf(&buffer
, format
, args
);
147 // Fail if we could not format the message
151 // Send everything to the context logger
152 pakfire_ctx_log(build
->ctx
, priority
, file
, line
, function
, "%s", buffer
);
154 // Call the build logger callback
155 if (build
->callbacks
.log
)
156 r
= build
->callbacks
.log(build
, build
->callbacks
.log_data
, priority
, error
,
157 file
, line
, function
, "%s", buffer
);
168 #define BUILD_LOG_ERRNO(build, priority, r, arg...) \
169 pakfire_build_log(build, priority, r, __FILE__, __LINE__, __FUNCTION__, ## arg)
170 #define BUILD_LOG(build, priority, arg...) BUILD_LOG_ERRNO(build, priority, 0, ## arg)
172 #define BUILD_INFO_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_INFO, r, ## arg)
173 #define BUILD_ERROR_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_ERR, r, ## arg)
174 #define BUILD_DEBUG_ERRNO(build, r, arg...) BUILD_LOG_ERRNO(build, LOG_DEBUG, r, ## arg)
176 #define BUILD_INFO(build, arg...) BUILD_INFO_ERRNO(build, 0, ## arg)
177 #define BUILD_ERROR(build, arg...) BUILD_ERROR_ERRNO(build, 0, ## arg)
178 #define BUILD_DEBUG(build, arg...) BUILD_DEBUG_ERRNO(build, 0, ## arg)
180 static int pakfire_build_has_flag(struct pakfire_build
* build
, int flag
) {
181 return build
->flags
& flag
;
184 static double pakfire_build_duration(struct pakfire_build
* build
) {
188 // What time is it now?
189 r
= clock_gettime(CLOCK_MONOTONIC
, &now
);
193 return pakfire_timespec_delta(&now
, &build
->time_start
);
196 static int pakfire_build_jail_log_callback(struct pakfire
* pakfire
,
197 void* data
, int priority
, const char* line
, size_t length
) {
198 struct pakfire_build
* build
= data
;
200 // Get the runtime of the build
201 const double t
= pakfire_build_duration(build
);
205 const unsigned int h
= (unsigned int)t
/ 3600;
206 const unsigned int m
= (unsigned int)t
% 3600 / 60;
207 const unsigned int s
= (unsigned int)t
% 60;
208 const unsigned int ms
= (unsigned int)(t
* 1000.0) % 1000;
211 return BUILD_LOG(build
, priority
, "[%02d:%02d:%02d.%04d] %.*s", h
, m
, s
, ms
, length
, line
);
214 return BUILD_LOG(build
, priority
, "[ %02d:%02d.%04d] %.*s", m
, s
, ms
, length
, line
);
217 return BUILD_LOG(build
, priority
, "[ %02d.%04d] %.*s", s
, ms
, length
, line
);
220 static int __pakfire_build_setup_repo(struct pakfire
* pakfire
,
221 struct pakfire_repo
* repo
, void* p
) {
226 struct pakfire_build
* build
= (struct pakfire_build
*)p
;
228 // Skip processing the installed repository
229 if (pakfire_repo_is_installed_repo(repo
))
232 // Skip processing any other internal repositories
233 if (pakfire_repo_is_internal(repo
))
236 const char* name
= pakfire_repo_get_name(repo
);
238 BUILD_DEBUG(build
, "Exporting repository configuration for '%s'\n", name
);
240 // Make path for configuration file
241 r
= pakfire_path(build
->pakfire
, path
, PAKFIRE_CONFIG_DIR
"/repos/%s.repo", name
);
243 BUILD_ERROR(build
, "Could not make repository configuration path for %s: %m\n", name
);
247 // Create the parent directory
248 r
= pakfire_mkparentdir(path
, 0755);
252 // Open the repository configuration
253 f
= fopen(path
, "w");
255 BUILD_ERROR(build
, "Could not open %s for writing: %m\n", path
);
259 // Write repository configuration
260 r
= pakfire_repo_write_config(repo
, f
);
262 BUILD_ERROR(build
, "Could not write repository configuration for %s: %m\n", name
);
266 // Bind-mount any local repositories
267 if (pakfire_repo_is_local(repo
)) {
268 const char* _path
= pakfire_repo_get_path(repo
);
270 // Bind-mount the repository data read-only
271 if (pakfire_path_exists(_path
)) {
272 r
= pakfire_jail_bind(build
->jail
, _path
, _path
, MS_RDONLY
);
274 BUILD_ERROR(build
, "Could not bind-mount the repository at %s: %m\n", _path
);
288 This function enables the local repository so that it can be accessed by
289 a pakfire instance running inside the chroot.
291 static int pakfire_build_enable_repos(struct pakfire_build
* build
) {
292 return pakfire_repo_walk(build
->pakfire
, __pakfire_build_setup_repo
, build
);
296 Drops the user into a shell
298 static int pakfire_build_shell(struct pakfire_build
* build
) {
301 // Export local repository if running in interactive mode
302 r
= pakfire_build_enable_repos(build
);
307 return pakfire_jail_shell(build
->jail
);
310 static int pakfire_build_read_script(struct pakfire_build
* build
,
311 const char* filename
, char** buffer
, size_t* length
) {
316 // Compose the source path
317 r
= pakfire_path_append(path
, PAKFIRE_SCRIPTS_DIR
, filename
);
319 ERROR(build
->pakfire
, "Could not compose path for script '%s': %m\n", filename
);
323 BUILD_DEBUG(build
, "Reading script from %s...\n", path
);
326 f
= fopen(path
, "r");
328 BUILD_ERROR(build
, "Could not open script %s: %m\n", path
);
332 // Read the file into a the buffer
333 r
= pakfire_read_file_into_buffer(f
, buffer
, length
);
335 BUILD_ERROR(build
, "Could not read script: %m\n");
346 static int pakfire_build_run_script(
347 struct pakfire_build
* build
,
348 const char* filename
,
349 const char* args
[]) {
355 BUILD_DEBUG(build
, "Running build script '%s'...\n", filename
);
358 r
= pakfire_build_read_script(build
, filename
, &script
, &length
);
360 ERROR(build
->pakfire
, "Could not read script %s: %m\n", filename
);
364 // Execute the script
365 r
= pakfire_jail_exec_script(build
->jail
, script
, length
, args
);
367 BUILD_ERROR(build
, "Script '%s' failed with status %d\n", filename
, r
);
375 struct pakfire_find_deps_ctx
{
376 struct pakfire_build
* build
;
377 struct pakfire_package
* pkg
;
379 struct pakfire_scriptlet
* scriptlet
;
381 const pcre2_code
* filter
;
383 struct pakfire_filelist
* filelist
;
387 static int pakfire_build_make_filter(struct pakfire_build
* build
, pcre2_code
** regex
,
388 struct pakfire_parser
* makefile
, const char* namespace, const char* filter
) {
389 char* pattern
= NULL
;
393 pattern
= pakfire_parser_get(makefile
, namespace, filter
);
395 // Nothing if to if there is no or an empty pattern
396 if (!pattern
|| !*pattern
)
399 DEBUG(build
->pakfire
, "Found filter for %s: %s\n", filter
, pattern
);
401 // Compile the regular expression
402 r
= pakfire_compile_regex(build
->pakfire
, regex
, pattern
);
413 static int pakfire_build_send_filelist(struct pakfire_ctx
* ctx
,
414 struct pakfire_jail
* jail
, void* data
, int fd
) {
415 struct pakfire_find_deps_ctx
* p
= (struct pakfire_find_deps_ctx
*)data
;
416 struct pakfire_file
* file
= NULL
;
419 const size_t length
= pakfire_filelist_length(p
->filelist
);
421 // Check if we have reached the end of the filelist
425 // Fetch the next file
426 file
= pakfire_filelist_get(p
->filelist
, p
->i
);
428 CTX_DEBUG(ctx
, "Could not fetch file %u: %m\n", p
->i
);
433 // Fetch the path of the file
434 const char* path
= pakfire_file_get_path(file
);
436 CTX_ERROR(ctx
, "Received a file with an empty path\n");
441 // Skip files that don't match what we are looking for
442 if (p
->class && !pakfire_file_matches_class(file
, p
->class))
445 // Write path to stdin
446 r
= dprintf(fd
, "%s\n", path
);
451 // Move on to the next file
459 pakfire_file_unref(file
);
464 static int pakfire_build_process_deps(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
465 void* data
, const char* buffer
, const size_t length
) {
466 const struct pakfire_find_deps_ctx
* p
= (struct pakfire_find_deps_ctx
*)data
;
468 pcre2_match_data
* match
= NULL
;
471 // Nothing to do for an empty buffer
472 if (!buffer
|| !*buffer
)
475 // Copy the dependency to the stack (and remove the trailing newline)
476 r
= pakfire_string_format(dep
, "%.*s", (int)length
- 1, buffer
);
480 BUILD_DEBUG(p
->build
, "Processing dependency: %s\n", dep
);
482 // Filter out any dependencies that are provided by this package
483 if (p
->dep
== PAKFIRE_PKG_REQUIRES
) {
484 // If this is a file, we check if it is on the filelist
485 if (pakfire_filelist_contains(p
->filelist
, dep
))
488 // Otherwise check if this dependency is provided by this package
489 else if (pakfire_package_matches_dep(p
->pkg
, PAKFIRE_PKG_PROVIDES
, dep
))
493 // Check if this dependency should be filtered
495 match
= pcre2_match_data_create_from_pattern(p
->filter
, NULL
);
497 CTX_ERROR(ctx
, "Could not allocate PCRE match data: %m\n");
502 r
= pcre2_jit_match(p
->filter
, (PCRE2_SPTR
)dep
, length
- 1,
506 if (r
== PCRE2_ERROR_NOMATCH
) {
513 // Fetch the error message
514 r
= pcre2_get_error_message(r
, (PCRE2_UCHAR
*)error
, sizeof(error
));
516 BUILD_ERROR(p
->build
, "Could not fetch PCRE error message: %m\n");
521 BUILD_ERROR(p
->build
, "Could not match the filter: %s\n", error
);
527 BUILD_DEBUG(p
->build
, "Skipping dependency that has been filtered: %s\n", dep
);
534 r
= pakfire_package_add_dep(p
->pkg
, p
->dep
, buffer
);
536 BUILD_ERROR(p
->build
, "Could not process dependency '%s': %m\n", buffer
);
543 BUILD_DEBUG(p
->build
, "Skipping dependency that is provided by the package itself: %s\n", dep
);
547 pcre2_match_data_free(match
);
553 This function is a special way to run a script.
555 It will pipe the filelist into the standard input of the called script
556 and will read any dependencies from the standard output.
558 static int pakfire_build_find_deps(struct pakfire_build
* build
,
559 struct pakfire_package
* pkg
, int dep
, const char* script
,
560 struct pakfire_filelist
* filelist
, int class, const pcre2_code
* filter
) {
561 // Construct the context
562 struct pakfire_find_deps_ctx ctx
= {
570 .filelist
= filelist
,
575 // Skip calling the script if class doesn't match
576 if (class && !pakfire_filelist_matches_class(filelist
, class)) {
577 DEBUG(build
->pakfire
, "Skipping calling %s as class does not match\n", script
);
581 // Pass the buildroot as first argument
582 const char* args
[] = {
583 pakfire_relpath(build
->pakfire
, build
->buildroot
),
588 pakfire_jail_set_stdin_callback(build
->jail
, pakfire_build_send_filelist
, &ctx
);
589 pakfire_jail_set_stdout_callback(build
->jail
, pakfire_build_process_deps
, &ctx
);
592 r
= pakfire_build_run_script(build
, script
, args
);
594 BUILD_ERROR(build
, "%s returned with error %d\n", script
, r
);
599 static int pakfire_build_find_dependencies(struct pakfire_build
* build
,
600 struct pakfire_parser
* makefile
, const char* namespace,
601 struct pakfire_package
* pkg
, struct pakfire_filelist
* filelist
) {
602 pcre2_code
* filter_provides
= NULL
;
603 pcre2_code
* filter_requires
= NULL
;
606 // Fetch the provides filter
607 r
= pakfire_build_make_filter(build
, &filter_provides
,
608 makefile
, namespace, "filter_provides");
610 ERROR(build
->pakfire
, "Provides filter is broken: %m\n");
614 // Fetch the requires filter
615 r
= pakfire_build_make_filter(build
, &filter_requires
,
616 makefile
, namespace, "filter_requires");
618 ERROR(build
->pakfire
, "Requires filter is broken: %m\n");
623 r
= pakfire_build_find_deps(build
, pkg
,
624 PAKFIRE_PKG_PROVIDES
, "find-provides", filelist
, 0, filter_provides
);
628 // Find all Perl provides
629 r
= pakfire_build_find_deps(build
, pkg
,
630 PAKFIRE_PKG_PROVIDES
, "perl.prov", filelist
, PAKFIRE_FILE_PERL
, filter_provides
);
635 r
= pakfire_build_find_deps(build
, pkg
,
636 PAKFIRE_PKG_REQUIRES
, "find-requires", filelist
, 0, filter_requires
);
640 // Find all Perl requires
641 r
= pakfire_build_find_deps(build
, pkg
,
642 PAKFIRE_PKG_REQUIRES
, "perl.req", filelist
, PAKFIRE_FILE_PERL
, filter_requires
);
648 pcre2_code_free(filter_provides
);
650 pcre2_code_free(filter_requires
);
655 static int __pakfire_build_package_mark_config_files(
656 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
657 char** configfiles
= (char**)data
;
660 // Skip anything that isn't a regular file
661 if (pakfire_file_get_type(file
) == S_IFREG
)
665 const char* path
= pakfire_file_get_path(file
);
667 // Check if any configfile entry matches against this
668 for (char** configfile
= configfiles
; *configfile
; configfile
++) {
669 if (pakfire_string_startswith(path
, *configfile
)) {
670 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
682 static int pakfire_build_package_mark_config_files(struct pakfire_build
* build
,
683 struct pakfire_filelist
* filelist
, struct pakfire_parser
* makefile
, const char* namespace) {
684 char** configfiles
= NULL
;
687 // Fetch configfiles from makefile
688 r
= pakfire_parser_get_filelist(makefile
, namespace, "configfiles", &configfiles
, NULL
);
690 // If configfiles is not set, there is nothing to do
694 r
= pakfire_filelist_walk(filelist
, __pakfire_build_package_mark_config_files
,
699 for (char** configfile
= configfiles
; *configfile
; configfile
++)
707 static int pakfire_build_package_add_files(struct pakfire_build
* build
,
708 struct pakfire_parser
* makefile
, const char* buildroot
, const char* namespace,
709 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
710 struct pakfire_filelist
* filelist
= NULL
;
711 char** includes
= NULL
;
712 char** excludes
= NULL
;
715 // Fetch filelist from makefile
716 r
= pakfire_parser_get_filelist(makefile
, namespace, "files", &includes
, &excludes
);
718 // No files to package?
719 if (!includes
&& !excludes
)
722 // Allocate a new filelist
723 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
728 r
= pakfire_filelist_scan(filelist
, build
->buildroot
,
729 (const char**)includes
, (const char**)excludes
, PAKFIRE_FILELIST_EXTENDED_MATCHING
);
733 BUILD_DEBUG(build
, "%zu file(s) found\n", pakfire_filelist_length(filelist
));
735 // Nothing to do if the filelist is empty
736 if (pakfire_filelist_is_empty(filelist
))
740 pakfire_filelist_dump(filelist
, PAKFIRE_FILE_DUMP_FULL
);
743 r
= pakfire_build_find_dependencies(build
, makefile
, namespace, pkg
, filelist
);
745 BUILD_ERROR(build
, "Finding dependencies failed: %m\n");
749 // Mark configuration files
750 r
= pakfire_build_package_mark_config_files(build
, filelist
, makefile
, namespace);
754 // Add all files to the package
755 r
= pakfire_packager_add_files(packager
, filelist
);
761 pakfire_filelist_unref(filelist
);
763 for (char** include
= includes
; *include
; include
++)
768 for (char** exclude
= excludes
; *exclude
; exclude
++)
776 static int pakfire_build_send_scriptlet(struct pakfire_ctx
* ctx
, struct pakfire_jail
* jail
,
777 void* data
, int fd
) {
778 const struct pakfire_find_deps_ctx
* __ctx
= (struct pakfire_find_deps_ctx
*)data
;
781 // Fetch the scriptlet
782 const char* p
= pakfire_scriptlet_get_data(__ctx
->scriptlet
, &length
);
784 CTX_ERROR(ctx
, "Could not fetch scriptlet: %m\n");
788 // Write it into the pipe
789 ssize_t bytes_written
= write(fd
, p
, length
);
790 if (bytes_written
< 0) {
791 CTX_ERROR(ctx
, "Could not send scriptlet: %m\n");
798 static int pakfire_build_add_scriptlet_requires(struct pakfire_build
* build
,
799 struct pakfire_package
* pkg
, struct pakfire_scriptlet
* scriptlet
) {
802 struct pakfire_find_deps_ctx ctx
= {
805 .dep
= PAKFIRE_PKG_PREREQUIRES
,
806 .scriptlet
= scriptlet
,
810 pakfire_jail_set_stdin_callback(build
->jail
, pakfire_build_send_scriptlet
, &ctx
);
811 pakfire_jail_set_stdout_callback(build
->jail
, pakfire_build_process_deps
, &ctx
);
813 // Find all pre-requires
814 r
= pakfire_build_run_script(build
, "find-prerequires", NULL
);
822 static int pakfire_build_package_add_scriptlet(struct pakfire_build
* build
,
823 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
,
824 const char* type
, const char* data
) {
825 struct pakfire_scriptlet
* scriptlet
= NULL
;
829 // Wrap scriptlet into a shell script
830 r
= asprintf(&shell
, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data
);
834 // Create a scriptlet
835 r
= pakfire_scriptlet_create(&scriptlet
, build
->ctx
, type
, shell
, 0);
839 // Add it to the package
840 r
= pakfire_packager_add_scriptlet(packager
, scriptlet
);
842 BUILD_ERROR(build
, "Could not add scriptlet %s\n", type
);
846 // Add scriptlet requirements
847 r
= pakfire_build_add_scriptlet_requires(build
, pkg
, scriptlet
);
849 BUILD_ERROR(build
, "Could not add scriptlet requirements: %m\n");
858 pakfire_scriptlet_unref(scriptlet
);
865 static int pakfire_build_package_add_scriptlets(struct pakfire_build
* build
,
866 struct pakfire_parser
* makefile
, const char* namespace,
867 struct pakfire_package
* pkg
, struct pakfire_packager
* packager
) {
871 for (const char** type
= pakfire_scriptlet_types
; *type
; type
++) {
872 r
= pakfire_string_format(name
, "scriptlet:%s", *type
);
876 // Fetch the scriptlet
877 char* data
= pakfire_parser_get(makefile
, namespace, name
);
881 // Add it to the package
882 r
= pakfire_build_package_add_scriptlet(build
, pkg
, packager
, *type
, data
);
894 static int pakfire_build_package(struct pakfire_build
* build
, struct pakfire_parser
* makefile
,
895 const char* buildroot
, const char* namespace) {
896 struct pakfire_package
* pkg
= NULL
;
897 struct pakfire_packager
* packager
= NULL
;
901 // Expand the handle into the package name
902 char* name
= pakfire_parser_expand(makefile
, "packages", namespace);
904 ERROR(build
->pakfire
, "Could not get package name: %m\n");
908 BUILD_INFO(build
, "Building package '%s'...\n", name
);
909 BUILD_DEBUG(build
, " buildroot = %s\n", buildroot
);
911 // Fetch build architecture
912 const char* arch
= pakfire_get_arch(build
->pakfire
);
916 // Fetch package from makefile
917 r
= pakfire_parser_create_package(makefile
, &pkg
, NULL
, namespace, arch
);
919 BUILD_ERROR(build
, "Could not create package from makefile: %m\n");
924 const char* distribution
= pakfire_parser_get(makefile
, NULL
, "DISTRO_NAME");
926 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_DISTRO
, distribution
);
932 pakfire_package_set_uuid(pkg
, PAKFIRE_PKG_BUILD_ID
, build
->id
);
934 // Set source package
935 const char* source_name
= pakfire_parser_get(makefile
, NULL
, "name");
937 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_NAME
, source_name
);
943 const char* source_evr
= pakfire_parser_get(makefile
, NULL
, "evr");
945 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_EVR
, source_evr
);
951 r
= pakfire_package_set_string(pkg
, PAKFIRE_PKG_SOURCE_ARCH
, "src");
956 r
= pakfire_packager_create(&packager
, build
->pakfire
, pkg
);
961 r
= pakfire_build_package_add_files(build
, makefile
, buildroot
, namespace,
967 r
= pakfire_build_package_add_scriptlets(build
, makefile
, namespace,
972 const char* path
= pakfire_repo_get_path(build
->repo
);
974 // Write the finished package
975 r
= pakfire_packager_finish_to_directory(packager
, path
, NULL
);
977 BUILD_ERROR(build
, "pakfire_packager_finish() failed: %m\n");
981 // Cleanup all packaged files
982 r
= pakfire_packager_cleanup(packager
);
991 pakfire_packager_unref(packager
);
993 pakfire_package_unref(pkg
);
1000 static int pakfire_build_package_dump(struct pakfire_ctx
* ctx
,
1001 struct pakfire_package
* pkg
, void* p
) {
1002 struct pakfire_build
* build
= p
;
1004 char* dump
= pakfire_package_dump(pkg
, PAKFIRE_PKG_DUMP_LONG
);
1008 BUILD_INFO(build
, "%s\n", dump
);
1014 static int pakfire_build_packages(struct pakfire_build
* build
,
1015 struct pakfire_parser
* makefile
) {
1016 BUILD_INFO(build
, "Creating packages...");
1019 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1021 // Fetch a list all all packages
1022 char** packages
= pakfire_parser_list_namespaces(makefile
, "packages.package:*");
1024 BUILD_ERROR(build
, "Could not find any packages: %m\n");
1028 unsigned int num_packages
= 0;
1030 // Count how many packages we have
1031 for (char** package
= packages
; *package
; package
++)
1034 DEBUG(build
->pakfire
, "Found %u package(s)\n", num_packages
);
1036 // Build packages in reverse order
1037 for (int i
= num_packages
- 1; i
>= 0; i
--) {
1038 r
= pakfire_build_package(build
, makefile
, buildroot
, packages
[i
]);
1043 // Rescan the build repository to import all packages again
1044 r
= pakfire_repo_scan(build
->repo
, 0);
1048 // Create a new packagelist
1049 r
= pakfire_packagelist_create(&build
->packages
, build
->ctx
);
1053 // Fetch all packages
1054 r
= pakfire_repo_to_packagelist(build
->repo
, build
->packages
);
1059 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_package_dump
, build
);
1073 static int pakfire_build_stage(struct pakfire_build
* build
,
1074 struct pakfire_parser
* makefile
, const char* stage
) {
1075 char template[1024];
1077 // Prepare template for this stage
1078 int r
= pakfire_string_format(template, TEMPLATE
, stage
);
1082 // Fetch the environment
1083 char** envp
= pakfire_parser_make_environ(makefile
);
1085 // Create the build script
1086 char* script
= pakfire_parser_expand(makefile
, "build", template);
1088 BUILD_ERROR(build
, "Could not generate the build script for stage '%s': %m\n", stage
);
1092 BUILD_INFO(build
, "Running build stage '%s'\n", stage
);
1094 // Import environment
1095 // XXX is this a good idea?
1096 r
= pakfire_jail_import_env(build
->jail
, (const char**)envp
);
1098 BUILD_ERROR(build
, "Could not import environment: %m\n");
1102 #warning We are thworing away the output here. Do we want this?
1105 r
= pakfire_jail_exec_script(build
->jail
, script
, strlen(script
), NULL
);
1107 BUILD_ERROR(build
, "Build stage '%s' failed with status %d\n", stage
, r
);
1111 for (char** e
= envp
; *e
; e
++)
1122 PAKFIRE_BUILD_CLEANUP_FILES
= (1 << 0),
1123 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
= (1 << 1),
1124 PAKFIRE_BUILD_SHOW_PROGRESS
= (1 << 2),
1128 This helper function takes a callback which is expected to add any files
1129 to the given filelist which will optionally be all removed after.
1131 static int pakfire_build_post_process_files(struct pakfire_build
* build
,
1132 struct pakfire_filelist
* filelist
, const char* description
,
1133 int (*callback
)(struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
),
1135 struct pakfire_filelist
* removees
= NULL
;
1138 // Create a filelist with objects that need to be removed
1139 r
= pakfire_filelist_create(&removees
, build
->pakfire
);
1143 // Find all files that need to be removed
1144 r
= pakfire_filelist_walk(filelist
, callback
, removees
,
1145 (flags
& PAKFIRE_BUILD_SHOW_PROGRESS
) ? PAKFIRE_FILELIST_SHOW_PROGRESS
: 0);
1149 if (!pakfire_filelist_is_empty(removees
)) {
1151 BUILD_INFO(build
, "%s\n", description
);
1153 // Show all files which will be removed
1154 pakfire_filelist_dump(removees
, PAKFIRE_FILE_DUMP_FULL
|PAKFIRE_FILE_DUMP_ISSUES
);
1156 // Remove all files on the removee list
1157 if (flags
& PAKFIRE_BUILD_CLEANUP_FILES
) {
1158 r
= pakfire_filelist_cleanup(removees
, PAKFIRE_FILE_CLEANUP_TIDY
);
1162 // Remove all files from the filelist
1163 r
= pakfire_filelist_remove_all(filelist
, removees
);
1168 // Report an error if any files have been found
1169 if (flags
& PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
)
1175 pakfire_filelist_unref(removees
);
1180 static int __pakfire_build_remove_static_libraries(
1181 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1182 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1183 char path
[PATH_MAX
];
1186 // Find all static libraries
1187 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_STATIC_LIBRARY
)) {
1188 // Copy the filename
1189 r
= pakfire_string_set(path
, pakfire_file_get_abspath(file
));
1193 // Remove the extension
1194 r
= pakfire_path_replace_extension(path
, "so");
1198 // Only delete if there is a shared object with the same name
1199 if (pakfire_path_exists(path
))
1200 return pakfire_filelist_add(removees
, file
);
1206 static int pakfire_build_post_remove_static_libraries(
1207 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1208 return pakfire_build_post_process_files(build
, filelist
,
1209 "Removing static libaries...",
1210 __pakfire_build_remove_static_libraries
,
1211 PAKFIRE_BUILD_CLEANUP_FILES
);
1214 static int __pakfire_build_remove_libtool_archives(
1215 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1216 struct pakfire_filelist
* removees
= (struct pakfire_filelist
*)data
;
1218 // Find all libtool archive files
1219 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_LIBTOOL_ARCHIVE
))
1220 return pakfire_filelist_add(removees
, file
);
1225 static int pakfire_build_post_remove_libtool_archives(
1226 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1227 return pakfire_build_post_process_files(build
, filelist
,
1228 "Removing libtool archives...",
1229 __pakfire_build_remove_libtool_archives
,
1230 PAKFIRE_BUILD_CLEANUP_FILES
);
1233 static int __pakfire_build_check_broken_symlinks(
1234 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1235 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1238 // Ignore anything that isn't a symlink
1239 switch (pakfire_file_get_type(file
)) {
1241 if (!pakfire_file_symlink_target_exists(file
)) {
1242 r
= pakfire_filelist_add(broken
, file
);
1249 // Ignore anything that isn't a symlink
1257 static int pakfire_build_post_check_broken_symlinks(
1258 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1259 return pakfire_build_post_process_files(build
, filelist
,
1260 "Broken symlinks have been found:",
1261 __pakfire_build_check_broken_symlinks
,
1262 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
);
1269 static int __pakfire_build_post_check_files(
1270 struct pakfire
* pakfire
, struct pakfire_file
* file
, void* data
) {
1271 struct pakfire_filelist
* broken
= (struct pakfire_filelist
*)data
;
1275 // Check file for issues
1276 r
= pakfire_file_check(file
, &issues
);
1278 //BUILD_ERROR(build, "%s: File Check failed: %m\n", pakfire_file_get_path(file));
1282 // If any issues have been found, consider this file to be on the list
1284 r
= pakfire_filelist_add(broken
, file
);
1292 static int pakfire_build_post_check_files(
1293 struct pakfire_build
* build
, struct pakfire_filelist
* filelist
) {
1294 return pakfire_build_post_process_files(
1298 __pakfire_build_post_check_files
,
1299 PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY
|PAKFIRE_BUILD_SHOW_PROGRESS
);
1302 static int pakfire_build_run_post_build_checks(struct pakfire_build
* build
) {
1303 struct pakfire_filelist
* filelist
= NULL
;
1306 // Create a filelist of all files in the build
1307 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1309 BUILD_ERROR(build
, "Could not create filelist: %m\n");
1313 // Scan for all files in BUILDROOT
1314 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
, 0);
1318 // If the filelist is empty, we can are done
1319 if (pakfire_filelist_is_empty(filelist
)) {
1320 DEBUG(build
->pakfire
, "Empty BUILDROOT. Skipping post build checks...\n");
1325 // Remove any static libraries
1326 r
= pakfire_build_post_remove_static_libraries(build
, filelist
);
1330 // Remove any libtool archives
1331 r
= pakfire_build_post_remove_libtool_archives(build
, filelist
);
1335 // Check for any broken symlinks
1336 r
= pakfire_build_post_check_broken_symlinks(build
, filelist
);
1341 r
= pakfire_build_post_check_files(build
, filelist
);
1347 pakfire_filelist_unref(filelist
);
1352 static const char* post_build_scripts
[] = {
1353 "compress-man-pages",
1358 static int pakfire_build_run_post_build_scripts(struct pakfire_build
* build
) {
1360 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1362 // Set default arguments for build scripts
1363 const char* args
[] = {
1367 // Run them one by one
1368 for (const char** script
= post_build_scripts
; *script
; script
++) {
1369 int r
= pakfire_build_run_script(build
, *script
, args
);
1377 static void pakfire_build_free(struct pakfire_build
* build
) {
1378 if (build
->packages
)
1379 pakfire_packagelist_unref(build
->packages
);
1382 pakfire_repo_clean(build
->repo
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
1383 pakfire_repo_unref(build
->repo
);
1387 pakfire_jail_unref(build
->jail
);
1389 if (build
->cgroup
) {
1390 // Destroy the cgroup
1391 pakfire_cgroup_destroy(build
->cgroup
);
1394 pakfire_cgroup_unref(build
->cgroup
);
1398 pakfire_unref(build
->pakfire
);
1400 pakfire_ctx_unref(build
->ctx
);
1404 static int pakfire_build_parse_id(struct pakfire_build
* build
, const char* id
) {
1407 // Try parsing the Build ID
1409 r
= uuid_parse(id
, build
->id
);
1411 ERROR(build
->pakfire
, "Could not parse build ID '%s'\n", id
);
1415 // Otherwise initialize the Build ID with something random
1417 uuid_generate_random(build
->id
);
1420 // Store the ID as string, too
1421 uuid_unparse_lower(build
->id
, build
->_id
);
1427 Sets up a new cgroup for this build
1429 static int pakfire_build_setup_cgroup(struct pakfire_build
* build
) {
1430 struct pakfire_config
* config
= NULL
;
1431 char path
[PATH_MAX
];
1435 r
= pakfire_string_format(path
, "pakfire/build-%s", build
->_id
);
1437 ERROR(build
->pakfire
, "Could not compose path for cgroup: %m\n");
1441 // Create a new cgroup
1442 r
= pakfire_cgroup_open(&build
->cgroup
, build
->ctx
, path
,
1443 PAKFIRE_CGROUP_ENABLE_ACCOUNTING
);
1445 ERROR(build
->pakfire
, "Could not create cgroup for build %s: %m\n", build
->_id
);
1450 config
= pakfire_get_config(build
->pakfire
);
1454 // Guarantee some minimum memory
1455 size_t memory_guaranteed
= pakfire_config_get_bytes(config
, "build",
1456 "memory_guaranteed", PAKFIRE_BUILD_MEMORY_GUARANTEED
);
1457 if (memory_guaranteed
) {
1458 r
= pakfire_cgroup_set_guaranteed_memory(build
->cgroup
, memory_guaranteed
);
1464 size_t memory_limit
= pakfire_config_get_bytes(config
, "build", "memory_limit", 0);
1466 r
= pakfire_cgroup_set_memory_limit(build
->cgroup
, memory_limit
);
1472 size_t pid_limit
= pakfire_config_get_int(config
, "build",
1473 "pid_limit", PAKFIRE_BUILD_PID_LIMIT
);
1475 r
= pakfire_cgroup_set_pid_limit(build
->cgroup
, pid_limit
);
1482 pakfire_config_unref(config
);
1488 Sets up a new jail for this build
1490 static int pakfire_build_setup_jail(struct pakfire_build
* build
) {
1493 // Create a new jail
1494 r
= pakfire_jail_create(&build
->jail
, build
->pakfire
);
1496 ERROR(build
->pakfire
, "Could not create jail for build %s: %m\n", build
->_id
);
1500 // Connect the jail to our cgroup
1501 r
= pakfire_jail_set_cgroup(build
->jail
, build
->cgroup
);
1503 ERROR(build
->pakfire
, "Could not set cgroup for jail: %m\n");
1507 // Build everything with a slightly lower priority
1508 r
= pakfire_jail_nice(build
->jail
, 5);
1510 ERROR(build
->pakfire
, "Could not set nice level: %m\n");
1519 Sets up the ccache for this build
1521 static int pakfire_build_mount_ccache(struct pakfire_build
* build
) {
1524 // Do nothing if the ccache is disabled
1525 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
))
1528 // Check that the path is set
1529 if (!*build
->ccache_path
)
1532 // Make sure the path exists
1533 r
= pakfire_mkdir(build
->ccache_path
, 0755);
1535 ERROR(build
->pakfire
, "Could not create %s: %m\n", build
->ccache_path
);
1539 // Bind-mount the directory
1540 return pakfire_jail_bind(build
->jail
, build
->ccache_path
, CCACHE_DIR
,
1541 MS_NOSUID
|MS_NOEXEC
|MS_NODEV
);
1544 static int pakfire_build_setup_ccache(struct pakfire_build
* build
) {
1547 // Check if we want a ccache
1548 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
)) {
1549 DEBUG(build
->pakfire
, "ccache usage has been disabled for this build\n");
1551 // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself
1552 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DISABLE", "1");
1554 ERROR(build
->pakfire
, "Could not disable ccache: %m\n");
1562 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_DIR", CCACHE_DIR
);
1564 ERROR(build
->pakfire
, "Could not set ccache directory: %m\n");
1568 // Set CCACHE_TEMPDIR
1569 r
= pakfire_jail_set_env(build
->jail
, "CCACHE_TEMPDIR", "/tmp");
1571 ERROR(build
->pakfire
, "Could not set ccache tempdir: %m\n");
1575 // Set a default path
1576 r
= pakfire_cache_path(build
->pakfire
, build
->ccache_path
, "%s", "ccache");
1583 static int pakfire_build_setup_repo(struct pakfire_build
* build
) {
1584 char path
[PATH_MAX
] = PAKFIRE_TMP_DIR
"/pakfire-build-repo.XXXXXX";
1588 // Create a new repository
1589 r
= pakfire_repo_create(&build
->repo
, build
->pakfire
, PAKFIRE_REPO_RESULT
);
1591 ERROR(build
->pakfire
, "Could not create repository %s: %m", PAKFIRE_REPO_RESULT
);
1596 pakfire_repo_set_description(build
->repo
, _("Build Repository"));
1598 // Create a temporary directory
1599 const char* p
= pakfire_mkdtemp(path
);
1601 ERROR(build
->pakfire
, "Could not create a the build repository: %m\n");
1606 r
= pakfire_string_format(url
, "file://%s", path
);
1611 pakfire_repo_set_baseurl(build
->repo
, url
);
1616 static int pakfire_build_set_time_start(struct pakfire_build
* build
) {
1619 // Fetch current time
1620 r
= clock_gettime(CLOCK_MONOTONIC
, &build
->time_start
);
1622 ERROR(build
->pakfire
, "Could not fetch start time: %m\n");
1627 PAKFIRE_EXPORT
int pakfire_build_create(struct pakfire_build
** build
,
1628 struct pakfire
* pakfire
, const char* id
, int flags
) {
1631 // Allocate build object
1632 struct pakfire_build
* b
= calloc(1, sizeof(*b
));
1636 // Reference the context
1637 b
->ctx
= pakfire_ctx(pakfire
);
1639 // Reference pakfire
1640 b
->pakfire
= pakfire_ref(pakfire
);
1642 // Initialize reference counter
1649 r
= pakfire_build_set_time_start(b
);
1654 r
= pakfire_build_parse_id(b
, id
);
1659 r
= pakfire_build_setup_repo(b
);
1664 r
= pakfire_build_setup_cgroup(b
);
1669 r
= pakfire_build_setup_jail(b
);
1674 r
= pakfire_build_setup_ccache(b
);
1682 pakfire_build_free(b
);
1686 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_ref(struct pakfire_build
* build
) {
1692 PAKFIRE_EXPORT
struct pakfire_build
* pakfire_build_unref(struct pakfire_build
* build
) {
1693 if (--build
->nrefs
> 0)
1696 pakfire_build_free(build
);
1700 PAKFIRE_EXPORT
void pakfire_build_set_log_callback(struct pakfire_build
* build
,
1701 pakfire_build_log_callback callback
, void* data
) {
1702 build
->callbacks
.log
= callback
;
1703 build
->callbacks
.log_data
= data
;
1706 PAKFIRE_EXPORT
int pakfire_build_set_ccache_path(
1707 struct pakfire_build
* build
, const char* path
) {
1708 // Check if this can be called
1709 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_CCACHE
))
1712 // Check input value
1713 if (!path
|| !*path
)
1717 return pakfire_string_set(build
->ccache_path
, path
);
1720 PAKFIRE_EXPORT
int pakfire_build_set_target(
1721 struct pakfire_build
* build
, const char* target
) {
1722 return pakfire_string_set(build
->target
, target
);
1725 static int pakfire_build_install_packages(
1726 struct pakfire_build
* build
, int* snapshot_needs_update
) {
1727 struct pakfire_transaction
* transaction
= NULL
;
1728 char* problems
= NULL
;
1731 // Create a new transaction
1732 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
1736 // Install all build dependencies
1737 for (const char** p
= PAKFIRE_BUILD_PACKAGES
; *p
; p
++) {
1738 r
= pakfire_transaction_request(transaction
,
1739 PAKFIRE_JOB_INSTALL
, *p
, PAKFIRE_JOB_ESSENTIAL
);
1744 // Also update everything that has already been installed
1745 r
= pakfire_transaction_request(transaction
, PAKFIRE_JOB_SYNC
, NULL
, 0);
1749 // Solve the transaction
1750 r
= pakfire_transaction_solve(transaction
, 0, &problems
);
1752 BUILD_ERROR(build
, "Could not install build dependencies:\n%s\n", problems
);
1756 // If there are changes, we have to update the snapshot
1757 if (pakfire_transaction_count(transaction
))
1758 *snapshot_needs_update
= 1;
1760 // Run the transaction
1761 r
= pakfire_transaction_run(transaction
);
1767 pakfire_transaction_unref(transaction
);
1775 Initializes the build environment
1777 static int pakfire_build_init(struct pakfire_build
* build
) {
1780 // Don't do it again
1782 DEBUG(build
->pakfire
, "Build environment has already been initialized\n");
1786 const int use_snapshot
= !pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_SNAPSHOT
);
1788 // Tells us whether we need to (re-)create the snapshot
1789 int snapshot_needs_update
= 0;
1793 r
= pakfire_snapshot_restore(build
->pakfire
);
1798 // Install or update any build dependencies
1799 r
= pakfire_build_install_packages(build
, &snapshot_needs_update
);
1803 // Update the snapshot if there were changes
1804 if (use_snapshot
&& snapshot_needs_update
) {
1805 // Store the snapshot
1806 r
= pakfire_snapshot_store(build
->pakfire
);
1811 // Mark as initialized
1817 static int pakfire_build_read_makefile(struct pakfire_build
* build
,
1818 struct pakfire_parser
** parser
, struct pakfire_package
* package
) {
1819 char path
[PATH_MAX
];
1822 struct pakfire_parser_error
* error
= NULL
;
1824 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
1825 const char* name
= pakfire_package_get_string(package
, PAKFIRE_PKG_NAME
);
1827 // Compose path to makefile
1828 r
= pakfire_path(build
->pakfire
, path
, "/usr/src/packages/%s/%s.nm", nevra
, name
);
1833 r
= pakfire_read_makefile(parser
, build
->pakfire
, path
, &error
);
1836 BUILD_ERROR(build
, "Could not parse makefile %s: %s\n", path
,
1837 pakfire_parser_error_get_message(error
));
1839 BUILD_ERROR(build
, "Could not parse makefile %s: %m\n", path
);
1846 const char* buildroot
= pakfire_relpath(build
->pakfire
, build
->buildroot
);
1848 pakfire_parser_set(*parser
, NULL
, "BUILDROOT", buildroot
, 0);
1852 pakfire_parser_error_unref(error
);
1857 static int pakfire_build_perform(struct pakfire_build
* build
,
1858 struct pakfire_parser
* makefile
) {
1861 // Prepare the build
1862 r
= pakfire_build_stage(build
, makefile
, "prepare");
1866 // Perform the build
1867 r
= pakfire_build_stage(build
, makefile
, "build");
1872 if (!pakfire_build_has_flag(build
, PAKFIRE_BUILD_DISABLE_TESTS
)) {
1873 r
= pakfire_build_stage(build
, makefile
, "test");
1878 // Install everything
1879 r
= pakfire_build_stage(build
, makefile
, "install");
1883 // Run post build checks
1884 r
= pakfire_build_run_post_build_checks(build
);
1886 BUILD_ERROR(build
, "Post build checks failed\n");
1890 // Run post build scripts
1891 r
= pakfire_build_run_post_build_scripts(build
);
1899 // Drop to a shell for debugging
1900 if (pakfire_build_has_flag(build
, PAKFIRE_BUILD_INTERACTIVE
))
1901 pakfire_build_shell(build
);
1906 static int __pakfire_build_unpackaged_file(struct pakfire
* pakfire
,
1907 struct pakfire_file
* file
, void* p
) {
1908 struct pakfire_build
* build
= p
;
1910 char* s
= pakfire_file_dump(file
, PAKFIRE_FILE_DUMP_FULL
);
1912 BUILD_ERROR(build
, "%s\n", s
);
1919 static int pakfire_build_check_unpackaged_files(struct pakfire_build
* build
) {
1920 struct pakfire_filelist
* filelist
= NULL
;
1923 // Create a new filelist
1924 r
= pakfire_filelist_create(&filelist
, build
->pakfire
);
1928 // Scan for all files in BUILDROOT
1929 r
= pakfire_filelist_scan(filelist
, build
->buildroot
, NULL
, NULL
, 0);
1933 if (!pakfire_filelist_is_empty(filelist
)) {
1934 BUILD_ERROR(build
, "Unpackaged files found:\n");
1936 r
= pakfire_filelist_walk(filelist
, __pakfire_build_unpackaged_file
, build
, 0);
1946 pakfire_filelist_unref(filelist
);
1951 static int pakfire_build_install_package(struct pakfire_ctx
* ctx
,
1952 struct pakfire_package
* pkg
, void* p
) {
1953 struct pakfire_transaction
* transaction
= (struct pakfire_transaction
*)p
;
1955 return pakfire_transaction_request_package(transaction
,
1956 PAKFIRE_JOB_INSTALL
, pkg
, PAKFIRE_JOB_ESSENTIAL
);
1959 static int pakfire_build_install_test(struct pakfire_build
* build
) {
1960 struct pakfire_transaction
* transaction
= NULL
;
1961 char* problems
= NULL
;
1964 // Create a new transaction
1965 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
1970 r
= pakfire_packagelist_walk(build
->packages
, pakfire_build_install_package
, transaction
);
1972 // Solve the request
1973 r
= pakfire_transaction_solve(transaction
, PAKFIRE_SOLVE_SHOW_SOLUTIONS
, &problems
);
1981 BUILD_ERROR(build
, "Install test failed:\n%s\n", problems
);
1986 BUILD_ERROR(build
, "Install test failed: %m\n");
1997 static int pakfire_build_post_check(struct pakfire_build
* build
) {
2000 // Check for unpackaged files
2001 r
= pakfire_build_check_unpackaged_files(build
);
2005 // Perform install test
2006 r
= pakfire_build_install_test(build
);
2013 static int pakfire_build_copy_package(struct pakfire_ctx
* ctx
,
2014 struct pakfire_package
* pkg
, void* p
) {
2015 struct pakfire_archive
* archive
= NULL
;
2016 char path
[PATH_MAX
];
2019 const char* target
= (const char*)p
;
2024 // Fetch the package filename
2025 const char* filename
= pakfire_package_get_string(pkg
, PAKFIRE_PKG_FILENAME
);
2031 // Format the destination path
2032 r
= pakfire_string_format(path
, "%s/%s", target
, filename
);
2037 archive
= pakfire_package_get_archive(pkg
);
2043 // Copy it to its destination
2044 r
= pakfire_archive_copy(archive
, path
);
2050 pakfire_archive_unref(archive
);
2055 static int pakfire_build_copy_packages(struct pakfire_build
* build
) {
2056 struct pakfire_repo
* local
= NULL
;
2059 DEBUG(build
->pakfire
, "Copying built packages\n");
2061 // Fetch local repository
2062 local
= pakfire_get_repo(build
->pakfire
, PAKFIRE_REPO_LOCAL
);
2064 // Copy all packages to the target path
2065 if (*build
->target
) {
2066 r
= pakfire_packagelist_walk(build
->packages
,
2067 pakfire_build_copy_package
, build
->target
);
2072 // If we have a local repository, we copy all packages to it
2074 const char* path
= pakfire_repo_get_path(local
);
2076 r
= pakfire_packagelist_walk(build
->packages
,
2077 pakfire_build_copy_package
, (void*)path
);
2085 pakfire_repo_unref(local
);
2090 static int pakfire_build_install_source_package(
2091 struct pakfire_build
* build
, struct pakfire_package
* package
) {
2092 struct pakfire_transaction
* transaction
= NULL
;
2093 char* problems
= NULL
;
2096 // Create a new transaction
2097 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
2101 // Request to install all essential packages
2102 for (const char** p
= PAKFIRE_BUILD_PACKAGES
; *p
; p
++) {
2103 r
= pakfire_transaction_request(transaction
,
2104 PAKFIRE_JOB_INSTALL
, *p
, PAKFIRE_JOB_ESSENTIAL
);
2109 // Add the source package
2110 r
= pakfire_transaction_request_package(transaction
,
2111 PAKFIRE_JOB_INSTALL
, package
, PAKFIRE_JOB_ESSENTIAL
);
2115 // Solve the transaction
2116 r
= pakfire_transaction_solve(transaction
, 0, &problems
);
2119 BUILD_ERROR(build
, "Could not install the source package:\n%s\n", problems
);
2124 // Set how many packages have been changed
2125 const size_t changes
= pakfire_transaction_count(transaction
);
2127 // Sanity check to see if we actually try to install anything
2129 BUILD_ERROR(build
, "The source package did not get installed\n");
2134 // Run the transaction
2135 r
= pakfire_transaction_run(transaction
);
2141 pakfire_transaction_unref(transaction
);
2148 PAKFIRE_EXPORT
int pakfire_build_exec(struct pakfire_build
* build
, const char* path
) {
2149 struct pakfire_package
* package
= NULL
;
2150 struct pakfire_parser
* makefile
= NULL
;
2151 char* buildroot
= NULL
;
2152 char* problems
= NULL
;
2153 char duration
[TIME_STRING_MAX
];
2156 // Fetch architecture
2157 const char* arch
= pakfire_get_arch(build
->pakfire
);
2160 r
= pakfire_path(build
->pakfire
, build
->buildroot
, "%s",
2161 PAKFIRE_TMP_DIR
"/pakfire-buildroot.XXXXXX");
2165 // Open the source package
2166 r
= pakfire_commandline_add(build
->pakfire
, path
, &package
);
2170 const char* nevra
= pakfire_package_get_string(package
, PAKFIRE_PKG_NEVRA
);
2171 const char* uuid
= pakfire_package_get_string(package
, PAKFIRE_PKG_UUID
);
2173 BUILD_INFO(build
, "Building %s (%s)...\n", nevra
, uuid
);
2175 // Check if this package can be build in this environment
2176 if (!pakfire_package_supports_build_arch(package
, arch
)) {
2177 ERROR(build
->pakfire
, "%s does not support being built on %s\n", nevra
, arch
);
2182 // Perform an install check to see whether we can build this at all
2183 r
= pakfire_package_installcheck(package
, &problems
, 0);
2185 BUILD_ERROR(build
, "Cannot build %s:\n%s\n", nevra
, problems
);
2189 // Initialize the build environment
2190 r
= pakfire_build_init(build
);
2194 // Install the source package
2195 r
= pakfire_build_install_source_package(build
, package
);
2197 BUILD_ERROR(build
, "Could not install the source package: %m\n");
2202 r
= pakfire_build_mount_ccache(build
);
2204 BUILD_ERROR(build
, "Could not mount the ccache: %m\n");
2209 buildroot
= pakfire_mkdtemp(build
->buildroot
);
2211 BUILD_ERROR(build
, "Could not create BUILDROOT: %m\n");
2215 // Open the makefile
2216 r
= pakfire_build_read_makefile(build
, &makefile
, package
);
2220 // Perform the actual build
2221 r
= pakfire_build_perform(build
, makefile
);
2225 // Create the packages
2226 r
= pakfire_build_packages(build
, makefile
);
2228 BUILD_ERROR(build
, "Could not create packages: %m\n");
2232 // Perform post build checks
2233 r
= pakfire_build_post_check(build
);
2237 // Copy packages to their destination
2238 r
= pakfire_build_copy_packages(build
);
2243 r
= pakfire_format_time(duration
, pakfire_build_duration(build
));
2247 BUILD_INFO(build
, "Build successfully completed in %s\n", duration
);
2251 pakfire_parser_unref(makefile
);
2253 pakfire_package_unref(package
);
2257 // Cleanup buildroot
2259 pakfire_rmtree(buildroot
, 0);
2264 static int pakfire_build_mkimage_install_deps(struct pakfire_build
* build
,
2266 struct pakfire_transaction
* transaction
= NULL
;
2267 char requires
[NAME_MAX
];
2268 char* problems
= NULL
;
2272 r
= pakfire_string_format(requires
, "mkimage(%s)", type
);
2276 // Create a new transaction
2277 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
2279 ERROR(build
->pakfire
, "Could not create transaction: %m\n");
2283 // Add requires to the request
2284 r
= pakfire_transaction_request(transaction
,
2285 PAKFIRE_JOB_INSTALL
, requires
, PAKFIRE_JOB_ESSENTIAL
);
2287 ERROR(build
->pakfire
, "Could not add '%s' to the transaction: %m\n", requires
);
2291 // Solve the request
2292 r
= pakfire_transaction_solve(transaction
, 0, &problems
);
2294 ERROR(build
->pakfire
, "Could not solve the request:\n%s\n", problems
);
2298 // Run the transaction
2299 r
= pakfire_transaction_run(transaction
);
2305 pakfire_transaction_unref(transaction
);
2312 static int pakfire_build_collect_packages(struct pakfire_build
* build
, const char* path
) {
2313 struct pakfire_transaction
* transaction
= NULL
;
2314 char* problems
= NULL
;
2318 // Create a new transaction
2319 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
2321 ERROR(build
->pakfire
, "Could not create transaction: %m\n");
2326 // Install the base system
2327 r
= pakfire_transaction_request(transaction
,
2328 PAKFIRE_JOB_INSTALL
, "ipfire-release", PAKFIRE_JOB_ESSENTIAL
);
2330 ERROR(build
->pakfire
, "Could not install 'ipfire-release': %m\n");
2334 // Solve the transaction
2335 r
= pakfire_transaction_solve(transaction
, 0, &problems
);
2337 ERROR(build
->pakfire
, "Could not solve request:\n%s\n", problems
);
2341 // Empty transaction?
2342 if (!pakfire_transaction_count(transaction
)) {
2343 ERROR(build
->pakfire
, "The transaction is unexpectedly empty\n");
2348 // Dump the transaction
2349 p
= pakfire_transaction_dump(transaction
, 80);
2351 ERROR(build
->pakfire
, "Could not dump the transaction: %m\n");
2357 INFO(build
->pakfire
, "%s\n", p
);
2359 // Download all packages
2360 r
= pakfire_transaction_download(transaction
);
2362 ERROR(build
->pakfire
, "Could not download the transaction: %m\n");
2366 // Create a repository with all packages in this transaction
2367 r
= pakfire_transaction_compose_repo(transaction
, NULL
, path
);
2369 ERROR(build
->pakfire
, "Could not create repository: %m\n");
2373 // XXX Should we perform installcheck here?
2377 pakfire_transaction_unref(transaction
);
2386 PAKFIRE_EXPORT
int pakfire_build_mkimage(struct pakfire_build
* build
,
2387 const char* type
, FILE* f
) {
2389 char packagesdir
[PATH_MAX
];
2390 char path
[PATH_MAX
];
2398 // Create a path inside the build environment
2399 r
= pakfire_path(build
->pakfire
, path
, "%s",
2400 PAKFIRE_TMP_DIR
"/pakfire-image.XXXXXX");
2404 // Allocate a temporary file
2405 t
= pakfire_mktemp(path
, 0600);
2407 ERROR(build
->pakfire
, "Could not allocate a temporary file: %m\n");
2412 // Create a path for all packages
2413 r
= pakfire_path(build
->pakfire
, packagesdir
, "%s",
2414 PAKFIRE_TMP_DIR
"/pakfire-packages.XXXXXX");
2418 p
= pakfire_mkdtemp(packagesdir
);
2422 // Collect all packages
2423 r
= pakfire_build_collect_packages(build
, packagesdir
);
2427 // Initialize the build environment
2428 r
= pakfire_build_init(build
);
2432 // Install all dependencies
2433 r
= pakfire_build_mkimage_install_deps(build
, type
);
2437 const char* args
[] = {
2439 pakfire_relpath(build
->pakfire
, path
),
2440 pakfire_relpath(build
->pakfire
, packagesdir
),
2444 // Run the mkimage script
2445 r
= pakfire_build_run_script(build
, "mkimage", args
);
2449 // Copy data to its destination
2450 r
= pakfire_copy(build
->pakfire
, t
, f
);
2458 // Unlink the temporary file
2462 // Remove all packages
2463 pakfire_rmtree(packagesdir
, 0);
2468 int pakfire_build_clean(struct pakfire
* pakfire
, int flags
) {
2469 struct pakfire_repo
* local
= NULL
;
2472 // Fetch local repository
2473 local
= pakfire_get_repo(pakfire
, PAKFIRE_REPO_LOCAL
);
2475 ERROR(pakfire
, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL
);
2479 // Destroy everything in it
2480 r
= pakfire_repo_clean(local
, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY
);
2486 pakfire_repo_unref(local
);
2491 static int pakfire_build_install(struct pakfire_build
* build
, const char** packages
) {
2492 struct pakfire_transaction
* transaction
= NULL
;
2493 char* problems
= NULL
;
2496 // Create a new transaction
2497 r
= pakfire_transaction_create(&transaction
, build
->pakfire
, 0);
2501 // Install all packages
2502 for (const char** p
= packages
; *p
; p
++) {
2503 r
= pakfire_transaction_request(transaction
, PAKFIRE_JOB_INSTALL
, *p
, 0);
2508 // Solve the transaction
2509 r
= pakfire_transaction_solve(transaction
, 0, &problems
);
2511 ERROR(build
->pakfire
, "Could not install packages:\n%s\n", problems
);
2515 // Run the transaction
2516 r
= pakfire_transaction_run(transaction
);
2522 pakfire_transaction_unref(transaction
);
2530 This is a convenience function that sets up a build environment and
2531 then drops the user into an interactive shell.
2533 PAKFIRE_EXPORT
int pakfire_shell(struct pakfire
* pakfire
, const char** packages
, int flags
) {
2534 struct pakfire_build
* build
= NULL
;
2537 // Shells are always interactive
2538 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
2540 // Create a new build environment
2541 r
= pakfire_build_create(&build
, pakfire
, NULL
, flags
);
2543 ERROR(pakfire
, "Could not create build: %m\n");
2547 // Initialize the build environment
2548 r
= pakfire_build_init(build
);
2552 // Install any additional packages
2554 r
= pakfire_build_install(build
, packages
);
2560 r
= pakfire_build_shell(build
);
2564 pakfire_build_unref(build
);