]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/build.c
package: Don't return void
[people/stevee/pakfire.git] / src / libpakfire / build.c
CommitLineData
1a276007
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2021 Pakfire development team #
5# #
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. #
10# #
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. #
15# #
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/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
01b29895 22#include <glob.h>
1a276007 23#include <stdlib.h>
22a0733e 24#include <sys/mount.h>
cee6363a 25#include <unistd.h>
57e2cf99 26#include <uuid/uuid.h>
1a276007
MT
27
28#include <pakfire/build.h>
29#include <pakfire/execute.h>
30#include <pakfire/dist.h>
ae7968a7 31#include <pakfire/file.h>
1a276007 32#include <pakfire/logging.h>
4c07774f 33#include <pakfire/package.h>
48c6f2e7 34#include <pakfire/packager.h>
1a276007
MT
35#include <pakfire/parser.h>
36#include <pakfire/private.h>
4651122b 37#include <pakfire/repo.h>
99a56775 38#include <pakfire/request.h>
106d2edd 39#include <pakfire/scriptlet.h>
1a276007
MT
40#include <pakfire/util.h>
41
42static const char* stages[] = {
43 "prepare",
44 "build",
45 "test",
46 "install",
47 NULL,
48};
49
50#define TEMPLATE \
51 "#!/bin/bash --login\n" \
52 "\n" \
53 "set -e\n" \
54 "set -x\n" \
55 "\n" \
56 "%%{_%s}\n" \
57 "\n" \
58 "exit 0\n"
59
ac4c607b 60static int pakfire_build_run_script(struct pakfire* pakfire, const char* filename, const char* args[],
8d0f3a35
MT
61 pakfire_execute_logging_callback logging_callback, void* data) {
62 char* script = NULL;
63 size_t size = 0;
64 char path[PATH_MAX];
65
66 DEBUG(pakfire, "Running build script '%s'...\n", filename);
67
68 // Make the source path
69 pakfire_path_join(path, PAKFIRE_SCRIPTS_DIR, filename);
70
71 // Open the source script
72 FILE* f = fopen(path, "r");
73 if (!f) {
b1772bfb 74 ERROR(pakfire, "Could not open %s: %m\n", path);
8d0f3a35
MT
75 return 1;
76 }
77
78 // Read the script into memory
79 int r = pakfire_read_file_into_buffer(f, &script, &size);
80 if (r) {
b1772bfb 81 ERROR(pakfire, "Could not read script into memory: %m\n");
8d0f3a35
MT
82 goto ERROR;
83 }
84
85 // Execute it
29f2151d 86 r = pakfire_execute_script(pakfire, script, size, args, NULL, 0, logging_callback, data);
8d0f3a35
MT
87 if (r) {
88 ERROR(pakfire, "Script '%s' failed with status %d\n", filename, r);
89 }
90
91ERROR:
92 if (script)
93 free(script);
94
95 return r;
96}
97
5b0b3dc2
MT
98static int find_dependency(char** haystack, const char* needle) {
99 if (!needle) {
100 errno = EINVAL;
101 return -1;
102 }
103
104 if (!haystack)
105 return 0;
106
107 for (char** element = haystack; *element; element++) {
108 if (strcmp(needle, *element) == 0)
109 return 1;
110 }
111
112 return 0;
113}
114
ac4c607b 115static int pakfire_build_find_dependencies(struct pakfire* pakfire,
1bbbfb9e 116 struct pakfire_package* pkg, struct pakfire_filelist* filelist, const char* buildroot) {
5b0b3dc2
MT
117 char** provides = NULL;
118 char** requires = NULL;
119 char path[PATH_MAX];
120
121 // Allocate path to write the filelist to
122 int r = pakfire_make_path(pakfire, path, "tmp/.pakfire-filelist.XXXXXX");
123 if (r < 0)
124 return 1;
125
126 // Create a temporary file
127 FILE* f = pakfire_mktemp(path);
128 if (!f)
129 goto ERROR;
130
131 // Write filelist to the temporary file
132 r = pakfire_filelist_export(filelist, f);
133 fclose(f);
134 if (r) {
b1772bfb 135 ERROR(pakfire, "Could not export filelist: %m\n");
5b0b3dc2
MT
136 goto ERROR;
137 }
138
139 const char* root = pakfire_get_path(pakfire);
140
141 // Pass buildroot and the filelist as arguments
142 const char* args[] = {
143 buildroot, pakfire_path_relpath(root, path), NULL
144 };
145
146 // Find all provides
147 r = pakfire_build_run_script(pakfire, "find-provides", args,
148 pakfire_execute_capture_stdout_to_array, &provides);
149 if (r) {
150 ERROR(pakfire, "find-provides returned with error %d\n", r);
151 goto ERROR;
152 }
153
154 // Find all requires
155 r = pakfire_build_run_script(pakfire, "find-requires", args,
156 pakfire_execute_capture_stdout_to_array, &requires);
157 if (r) {
158 ERROR(pakfire, "find-requires returned with error %d\n", r);
159 goto ERROR;
160 }
161
162 // Add all provides to the package
163 if (provides) {
164 for (char** element = provides; *element; element++) {
165 DEBUG(pakfire, "Adding provides: %s\n", *element);
166 pakfire_package_add_provides(pkg, *element);
167 }
168 }
169
170 // Add all requires to the package
171 if (requires) {
172 for (char** element = requires; *element; element++) {
173 // Skip adding this requirement if also provided by this package
174 if (find_dependency(provides, *element))
175 continue;
176
177 DEBUG(pakfire, "Adding requires: %s\n", *element);
178 pakfire_package_add_requires(pkg, *element);
179 }
180 }
181
182 // Success
183 r = 0;
184
185ERROR:
186 if (provides) {
187 for (char** element = provides; *element; element++)
188 free(*element);
189 free(provides);
190 }
191 if (requires) {
192 for (char** element = requires; *element; element++)
193 free(*element);
194 free(requires);
195 }
196 unlink(path);
197
198 return r;
199}
200
73543ae3
MT
201static int append_to_array(const char*** array, const char* s) {
202 unsigned int length = 0;
203
204 // Determine the length of the existing array
205 if (*array) {
206 for (const char** element = *array; *element; element++)
207 length++;
208 }
209
210 // Allocate space
211 *array = reallocarray(*array, length + 2, sizeof(**array));
212 if (!*array)
213 return 1;
214
215 // Append s and terminate the array
216 (*array)[length] = s;
217 (*array)[length + 1] = NULL;
218
219 return 0;
220}
221
ac4c607b 222static int pakfire_build_package_add_files(struct pakfire* pakfire, struct pakfire_parser* makefile,
31480bee 223 const char* buildroot, const char* namespace, struct pakfire_package* pkg,
5b0b3dc2 224 struct pakfire_packager* packager) {
1bbbfb9e 225 struct pakfire_filelist* filelist = NULL;
73543ae3
MT
226 char path[PATH_MAX];
227 int r = 1;
228
229 char** files = NULL;
230 const char** includes = NULL;
231 const char** excludes = NULL;
232
233 // Fetch filelist from makefile
234 files = pakfire_parser_get_split(makefile, namespace, "files", '\n');
235
236 // No files to package?
237 if (!files)
238 return 0;
239
73543ae3
MT
240 // Convert to absolute path
241 pakfire_make_path(pakfire, path, buildroot);
242
243 // Split into includes and excludes
244 for (char** file = files; *file; file++) {
245 if (**file == '!')
246 r = append_to_array(&excludes, *file);
247 else
248 r = append_to_array(&includes, *file);
249 if (r)
250 goto ERROR;
251 }
252
253 // Allocate a new filelist
254 r = pakfire_filelist_create(&filelist, pakfire);
255 if (r)
256 goto ERROR;
257
258 // Scan for files
259 r = pakfire_filelist_scan(filelist, path, includes, excludes);
260 if (r)
261 goto ERROR;
262
ae7968a7 263 const size_t length = pakfire_filelist_size(filelist);
73543ae3
MT
264 DEBUG(pakfire, "%zu file(s) found\n", length);
265
84556307
MT
266 // Nothing to do if the filelist is empty
267 if (!length)
268 goto ERROR;
269
5b0b3dc2
MT
270 // Find dependencies
271 r = pakfire_build_find_dependencies(pakfire, pkg, filelist, buildroot);
272 if (r) {
b1772bfb 273 ERROR(pakfire, "Finding dependencies failed: %m\n");
5b0b3dc2
MT
274 goto ERROR;
275 }
276
ae7968a7
MT
277 // Add all files to the package
278 for (unsigned int i = 0; i < length; i++) {
5803b5f6 279 struct pakfire_file* file = pakfire_filelist_get(filelist, i);
ae7968a7
MT
280
281 // Add the file to the package
282 r = pakfire_packager_add(
283 packager,
284 pakfire_file_get_abspath(file),
285 pakfire_file_get_path(file)
286 );
287 if (r) {
288 pakfire_file_unref(file);
289 goto ERROR;
290 }
291
3fca5032
MT
292 // Remove the file after it was packaged
293 r = pakfire_file_cleanup(file);
294 if (r) {
295 pakfire_file_unref(file);
296 goto ERROR;
297 }
298
ae7968a7
MT
299 pakfire_file_unref(file);
300 }
73543ae3
MT
301
302ERROR:
303 if (filelist)
304 pakfire_filelist_unref(filelist);
305 if (files) {
306 for (char** file = files; *file; file++)
307 free(*file);
308 free(files);
309 }
310 if (includes)
311 free(includes);
312 if (excludes)
313 free(excludes);
73543ae3
MT
314
315 return r;
316}
317
ac4c607b 318static int pakfire_build_add_scriptlet_requires(struct pakfire* pakfire, struct pakfire_package* pkg,
106d2edd
MT
319 struct pakfire_scriptlet* scriptlet) {
320 char** prerequires = NULL;
321 char path[PATH_MAX];
322 size_t size;
323 int r;
324
325 const char* root = pakfire_get_path(pakfire);
326
327 // Make filename
328 r = pakfire_make_path(pakfire, path, "tmp/.pakfire-scriptlet.XXXXXX");
329 if (r < 0)
330 return r;
331
332 // Fetch scriptlet payload
333 const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
334
335 // Create a temporary file
336 FILE* f = pakfire_mktemp(path);
337 if (!f)
338 return 1;
339
340 // Write scriptlet
341 ssize_t bytes_written = fwrite(data, 1, size, f);
342 if (bytes_written < 0) {
343 ERROR(pakfire, "Could not write to %s: %m\n", path);
344 fclose(f);
345 goto ERROR;
346 }
347
348 // Close file
349 fclose(f);
350
351 // Build commandline
352 const char* args[] = {
353 pakfire_path_relpath(root, path),
354 NULL,
355 };
356
357 // Find all pre-requires
358 r = pakfire_build_run_script(pakfire, "find-prerequires", args,
359 pakfire_execute_capture_stdout_to_array, &prerequires);
360 if (r)
361 goto ERROR;
362
363 // Add all pre-requires to the package
364 if (prerequires) {
365 for (char** element = prerequires; *element; element++) {
366 DEBUG(pakfire, "Adding pre-requires: %s\n", *element);
367 pakfire_package_add_prerequires(pkg, *element);
368 }
369 }
370
371ERROR:
372 if (r && *path)
373 unlink(path);
374 if (prerequires) {
375 for (char** element = prerequires; *element; element++)
376 free(*element);
377 free(prerequires);
378 }
379 return r;
380}
381
ac4c607b 382static int pakfire_build_package_add_scriptlet(struct pakfire* pakfire, struct pakfire_package* pkg,
106d2edd
MT
383 struct pakfire_packager* packager, const char* type, const char* data) {
384 struct pakfire_scriptlet* scriptlet = NULL;
385 char* shell = NULL;
386 int r;
387
388 // Wrap scriptlet into a shell script
389 r = asprintf(&shell, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data);
390 if (r < 0)
391 goto ERROR;
392
393 // Create a scriptlet
394 r = pakfire_scriptlet_create(&scriptlet, pakfire, type, shell, 0);
395 if (r)
396 goto ERROR;
397
398 // Add it to the package
399 r = pakfire_packager_add_scriptlet(packager, scriptlet);
400 if (r) {
401 ERROR(pakfire, "Could not add scriptlet %s\n", type);
402 goto ERROR;
403 }
404
405 // Add scriptlet requirements
406 r = pakfire_build_add_scriptlet_requires(pakfire, pkg, scriptlet);
407 if (r) {
b1772bfb 408 ERROR(pakfire, "Could not add scriptlet requirements: %m\n");
106d2edd
MT
409 goto ERROR;
410 }
411
412 // Success
413 r = 0;
414
415ERROR:
416 if (scriptlet)
417 pakfire_scriptlet_unref(scriptlet);
418 if (shell)
419 free(shell);
420
421 return r;
422}
423
ac4c607b 424static int pakfire_build_package_add_scriptlets(struct pakfire* pakfire, struct pakfire_parser* makefile,
31480bee 425 const char* namespace, struct pakfire_package* pkg, struct pakfire_packager* packager) {
106d2edd
MT
426 char name[NAME_MAX];
427 int r;
428
429 for (const char** type = pakfire_scriptlet_types; *type; type++) {
430 r = pakfire_string_format(name, "scriptlet:%s", *type);
431 if (r < 0)
432 return r;
433
434 // Fetch the scriptlet
435 char* data = pakfire_parser_get(makefile, namespace, name);
436 if (!data)
437 continue;
438
439 // Add it to the package
440 r = pakfire_build_package_add_scriptlet(pakfire, pkg, packager, *type, data);
441 if (r) {
442 free(data);
443 return r;
444 }
445
446 free(data);
447 }
448
449 return 0;
450}
451
ac4c607b 452static int pakfire_build_package(struct pakfire* pakfire, struct pakfire_parser* makefile,
57e2cf99 453 uuid_t* build_id, const char* buildroot, const char* namespace, const char* target) {
31480bee 454 struct pakfire_package* pkg = NULL;
48c6f2e7 455 struct pakfire_packager* packager = NULL;
73543ae3 456
a50bde9c
MT
457 int r = 1;
458
459 // Expand the handle into the package name
4c07774f 460 char* name = pakfire_parser_expand(makefile, "packages", namespace);
a50bde9c 461 if (!name) {
b1772bfb 462 ERROR(pakfire, "Could not get package name: %m\n");
a50bde9c
MT
463 goto ERROR;
464 }
465
466 INFO(pakfire, "Building package '%s'...\n", name);
467
4c07774f
MT
468 // Fetch build architecture
469 const char* arch = pakfire_get_arch(pakfire);
470 if (!arch)
471 goto ERROR;
472
4c07774f 473 // Fetch package from makefile
6ebd55e2 474 r = pakfire_parser_create_package(makefile, &pkg, NULL, namespace, arch);
4c07774f 475 if (r) {
b1772bfb 476 ERROR(pakfire, "Could not create package from makefile: %m\n");
4c07774f
MT
477 goto ERROR;
478 }
479
ca002cae
MT
480 // Set distribution
481 const char* distribution = pakfire_parser_get(makefile, NULL, "DISTRO_NAME");
482 if (distribution)
483 pakfire_package_set_distribution(pkg, distribution);
484
7996020a 485 // Set build ID
57e2cf99 486 pakfire_package_set_build_id_from_uuid(pkg, build_id);
7996020a 487
571539a7
MT
488 // Set source package
489 const char* source_name = pakfire_parser_get(makefile, NULL, "name");
490 if (source_name)
491 pakfire_package_set_source_name(pkg, source_name);
492
493 // Set source EVR
494 const char* source_evr = pakfire_parser_get(makefile, NULL, "evr");
495 if (source_evr)
496 pakfire_package_set_source_evr(pkg, source_evr);
497
498 // Set source arch
499 pakfire_package_set_source_arch(pkg, "src");
500
48c6f2e7 501 // Create a packager
5d7a93ec 502 r = pakfire_packager_create(&packager, pakfire, pkg);
48c6f2e7
MT
503 if (r)
504 goto ERROR;
505
73543ae3 506 // Add files
5b0b3dc2
MT
507 r = pakfire_build_package_add_files(pakfire, makefile, buildroot, namespace,
508 pkg, packager);
73543ae3
MT
509 if (r)
510 goto ERROR;
511
106d2edd
MT
512 // Add scriptlets
513 r = pakfire_build_package_add_scriptlets(pakfire, makefile, namespace, pkg, packager);
514 if (r)
515 goto ERROR;
516
ae7968a7 517 // Write the finished package
45448dbd 518 r = pakfire_packager_finish_to_directory(packager, target, NULL);
ae7968a7 519 if (r) {
b1772bfb 520 ERROR(pakfire, "pakfire_packager_finish() failed: %m\n");
ae7968a7
MT
521 goto ERROR;
522 }
523
4c07774f 524#ifdef ENABLE_DEBUG
23e22751 525 char* dump = pakfire_package_dump(pkg, PAKFIRE_PKG_DUMP_LONG);
4c07774f
MT
526 if (dump) {
527 DEBUG(pakfire, "%s\n", dump);
528 free(dump);
529 }
530#endif
a50bde9c
MT
531
532 // Success
533 r = 0;
534
535ERROR:
48c6f2e7
MT
536 if (packager)
537 pakfire_packager_unref(packager);
4c07774f
MT
538 if (pkg)
539 pakfire_package_unref(pkg);
a50bde9c
MT
540 if (name)
541 free(name);
542
543 return r;
544}
545
ac4c607b 546static int pakfire_build_packages(struct pakfire* pakfire, struct pakfire_parser* makefile,
57e2cf99 547 uuid_t* build_id, const char* buildroot, const char* target) {
a50bde9c
MT
548 DEBUG(pakfire, "Creating packages...");
549 int r = 1;
550
551 // Fetch a list all all packages
552 char** packages = pakfire_parser_list_namespaces(makefile, "packages.package:*");
553 if (!packages) {
b1772bfb 554 ERROR(pakfire, "Could not find any packages: %m\n");
a50bde9c
MT
555 goto ERROR;
556 }
557
558 unsigned int num_packages = 0;
559
560 // Count how many packages we have
561 for (char** package = packages; *package; package++)
562 num_packages++;
563
564 DEBUG(pakfire, "Found %d package(s)\n", num_packages);
565
566 // Build packages in reverse order
567 for (int i = num_packages - 1; i >= 0; i--) {
57e2cf99 568 r = pakfire_build_package(pakfire, makefile, build_id, buildroot, packages[i], target);
a50bde9c
MT
569 if (r)
570 goto ERROR;
571 }
572
573 // Success
574 r = 0;
575
576ERROR:
577 if (packages)
578 free(packages);
579
580 return r;
581}
582
ac4c607b 583static int pakfire_build_stage(struct pakfire* pakfire, struct pakfire_parser* makefile, const char* stage,
7d999600 584 pakfire_execute_logging_callback logging_callback, void* data) {
1a276007
MT
585 char template[1024];
586
587 // Prepare template for this stage
588 int r = pakfire_string_format(template, TEMPLATE, stage);
589 if (r < 0)
590 return r;
591
2ffd21f9
MT
592 // Fetch the environment
593 char** envp = pakfire_parser_make_environ(makefile);
594
1a276007
MT
595 // Create the build script
596 char* script = pakfire_parser_expand(makefile, "build", template);
597 if (!script) {
b1772bfb 598 ERROR(pakfire, "Could not generate the build script for stage '%s': %m\n", stage);
1a276007
MT
599 goto ERROR;
600 }
601
602 INFO(pakfire, "Running build stage '%s'\n", stage);
603
2ffd21f9 604 r = pakfire_execute_script(pakfire, script, strlen(script), NULL, envp, 0,
7d999600 605 logging_callback, data);
1a276007
MT
606 if (r) {
607 ERROR(pakfire, "Build stage '%s' failed with status %d\n", stage, r);
608 }
609
610ERROR:
2ffd21f9
MT
611 if (envp) {
612 for (char** e = envp; *e; e++)
613 free(*e);
614 free(envp);
615 }
1a276007
MT
616 if (script)
617 free(script);
618
619 return r;
620}
621
39f45b30
MT
622static const char* post_build_scripts[] = {
623 "remove-static-libs",
1f62ffae 624 "check-symlinks",
022b794e 625 "check-unsafe-files",
0b5f0bbc 626 "check-libraries",
16043831 627 "check-rpaths",
99aee237 628 "check-buildroot",
7e1fec6f 629 "check-include",
dd864160 630 "check-hardening",
ae703321 631 "check-interpreters",
2504194a 632 "check-fhs",
39f45b30 633 "compress-man-pages",
ffb65de6 634 "strip",
39f45b30
MT
635 NULL,
636};
637
ac4c607b 638static int pakfire_build_run_post_build_scripts(struct pakfire* pakfire, const char* buildroot,
39f45b30
MT
639 pakfire_execute_logging_callback logging_callback, void* data) {
640 // Set default arguments for build scripts
641 const char* args[] = {
642 buildroot, NULL
643 };
644
645 // Run them one by one
646 for (const char** script = post_build_scripts; *script; script++) {
647 int r = pakfire_build_run_script(pakfire, *script, args, logging_callback, data);
648 if (r)
649 return r;
650 }
651
652 return 0;
653}
654
ac4c607b 655static int pakfire_build_makefile(struct pakfire* pakfire, const char* path, const char* target,
57e2cf99
MT
656 uuid_t* build_id, int flags,
657 pakfire_execute_logging_callback logging_callback, void* data) {
657a5c72 658 struct pakfire_parser* makefile = NULL;
3d4011eb 659 char buildroot[PATH_MAX];
1a276007 660 struct pakfire_parser_error* error = NULL;
01b29895 661 int r = 1;
f0893704 662
3d4011eb
MT
663 const char* root = pakfire_get_path(pakfire);
664
665 // Create BUILDROOT
666 pakfire_make_path(pakfire, buildroot, "/tmp/.buildroot.XXXXXX");
667 if (!pakfire_mkdtemp(buildroot))
f0893704 668 goto ERROR;
3d4011eb
MT
669
670 // Make relative BUILDROOT path
671 const char* buildroot_rel = pakfire_path_relpath(root, buildroot);
672 if (!buildroot_rel)
f0893704 673 goto ERROR;
3d4011eb 674
1a276007 675 // Read makefile
3d4011eb 676 r = pakfire_read_makefile(&makefile, pakfire, path, &error);
1a276007
MT
677 if (r) {
678 if (error) {
679 ERROR(pakfire, "Could not parse makefile %s: %s\n", path,
680 pakfire_parser_error_get_message(error));
681 pakfire_parser_error_unref(error);
682 } else {
b1772bfb 683 ERROR(pakfire, "Could not parse makefile %s: %m\n", path);
1a276007
MT
684 }
685
686 goto ERROR;
687 }
688
3d4011eb 689 // Set BUILDROOT
fea2e884 690 pakfire_parser_set(makefile, NULL, "BUILDROOT", buildroot_rel, 0);
3d4011eb 691
1a276007
MT
692 // Run through all build stages
693 for (const char** stage = stages; *stage; stage++) {
23b93958 694 r = pakfire_build_stage(pakfire, makefile, *stage, logging_callback, data);
1a276007
MT
695 if (r) {
696 // Drop to a shell for debugging
f4e10417 697 if (pakfire_has_flag(pakfire, PAKFIRE_FLAGS_INTERACTIVE))
48dc31f7 698 pakfire_execute_shell(pakfire);
1a276007
MT
699
700 goto ERROR;
701 }
702 }
703
39f45b30
MT
704 // Run post build scripts
705 r = pakfire_build_run_post_build_scripts(pakfire, buildroot_rel, logging_callback, data);
8d0f3a35
MT
706 if (r)
707 goto ERROR;
708
a50bde9c 709 // Create the packages
57e2cf99 710 r = pakfire_build_packages(pakfire, makefile, build_id, buildroot_rel, target);
a50bde9c 711 if (r) {
b1772bfb 712 ERROR(pakfire, "Could not create packages: %m\n");
a50bde9c
MT
713 goto ERROR;
714 }
1a276007
MT
715
716ERROR:
717 if (makefile)
718 pakfire_parser_unref(makefile);
719
3d4011eb
MT
720 // Remove buildroot
721 pakfire_rmtree(buildroot, 0);
722
1a276007
MT
723 return r;
724}
725
ac4c607b 726PAKFIRE_EXPORT int pakfire_build(struct pakfire* pakfire, const char* path,
01b29895
MT
727 const char* target, const char* id, int flags,
728 pakfire_execute_logging_callback logging_callback, void* data) {
729 char makefiles[PATH_MAX];
cee6363a 730 char cwd[PATH_MAX];
57e2cf99 731 uuid_t build_id;
01b29895
MT
732 glob_t buffer;
733 int r = 1;
734
735 // Check for valid input
736 if (!path) {
737 errno = EINVAL;
738 return 1;
739 }
740
c6d462ed
MT
741 DEBUG(pakfire, "Building %s...\n", path);
742
57e2cf99
MT
743 // Try parsing the Build ID
744 if (id) {
745 r = uuid_parse(id, build_id);
c6d462ed
MT
746 if (r) {
747 ERROR(pakfire, "Could not parse build ID %s\n", id);
57e2cf99 748 return r;
c6d462ed 749 }
57e2cf99
MT
750
751 // Otherwise initialize the Build ID with something random
752 } else {
753 uuid_generate_random(build_id);
754 }
755
01b29895
MT
756 // The default target is the local repository path
757 if (!target) {
7ccac5e5 758 struct pakfire_repo* repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL);
cee6363a
MT
759 if (repo) {
760 target = pakfire_repo_get_path(repo);
761 pakfire_repo_unref(repo);
01b29895 762
cee6363a
MT
763 // If the repository could not be found, just write to the cwd
764 } else {
765 target = getcwd(cwd, sizeof(cwd));
766 }
01b29895
MT
767 }
768
14919022
MT
769 // Setup build environment
770 r = pakfire_build_setup(pakfire);
771 if (r)
772 return r;
773
01b29895
MT
774 const char* packages[] = {
775 path, NULL
776 };
777
778 // Install the package into the build environment
99a56775
MT
779 r = pakfire_install(pakfire, 0, packages, NULL, PAKFIRE_REQUEST_ESSENTIAL,
780 NULL, NULL, NULL);
01b29895
MT
781 if (r) {
782 ERROR(pakfire, "Could not install %s\n", path);
783 goto ERROR;
784 }
785
786 // Where are the makefiles located?
787 r = pakfire_make_path(pakfire, makefiles, "/usr/src/packages/*/*.nm");
788 if (r < 0)
789 goto ERROR;
790
791 // Find all makefiles
792 r = glob(makefiles, 0, NULL, &buffer);
793 if (r) {
794 ERROR(pakfire, "glob() on %s failed: %m\n", makefiles);
b631c2f2 795 globfree(&buffer);
01b29895
MT
796 goto ERROR;
797 }
798
799 // Iterate over all makefiles
800 for (unsigned int i = 0; i < buffer.gl_pathc; i++) {
57e2cf99 801 r = pakfire_build_makefile(pakfire, buffer.gl_pathv[i], target, &build_id, flags,
01b29895 802 logging_callback, data);
b631c2f2
MT
803 if (r) {
804 ERROR(pakfire, "Could not build %s: %m\n", buffer.gl_pathv[i]);
805 globfree(&buffer);
01b29895 806 goto ERROR;
b631c2f2 807 }
01b29895
MT
808 }
809
810ERROR:
01b29895
MT
811 return r;
812}
813
22a0733e
MT
814/*
815 This function enables the local repository so that it can be access by
816 a pakfire instance running inside the chroot.
817*/
818static int pakfire_build_enable_repos(struct pakfire* pakfire) {
819 char repopath[PATH_MAX];
820 FILE* f = NULL;
821 int r = 1;
822
823 // Fetch the local repository
824 struct pakfire_repo* repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL);
825 if (!repo) {
826 DEBUG(pakfire, "Could not find repository '%s': %m\n", PAKFIRE_REPO_LOCAL);
827 return 0;
828 }
829
830 // Fetch repository configuration
831 char* config = pakfire_repo_get_config(repo);
832 if (!config) {
833 ERROR(pakfire, "Could not generate repository configuration: %m\n");
834 goto ERROR;
835 }
836
837 const char* path = pakfire_repo_get_path(repo);
838
839 // Make sure the source directory exists
840 r = pakfire_mkdir(path, 0);
4e98e6bc 841 if (r && errno != EEXIST) {
22a0733e
MT
842 ERROR(pakfire, "Could not create repository directory %s: %m\n", path);
843 goto ERROR;
844 }
845
846 // Bind-mount the repository data read-only
847 r = pakfire_bind(pakfire, path, NULL, MS_RDONLY);
848 if (r) {
849 ERROR(pakfire, "Could not bind-mount the repository at %s: %m\n", path);
850 goto ERROR;
851 }
852
853 // Make path for configuration file
854 r = pakfire_make_path(pakfire, repopath,
3f559dd0 855 PAKFIRE_CONFIG_DIR "/repos/" PAKFIRE_REPO_LOCAL ".repo");
22a0733e
MT
856 if (r < 0)
857 goto ERROR;
858
859 // Open configuration file for writing
860 f = fopen(repopath, "w");
861 if (!f) {
862 ERROR(pakfire, "Could not open %s for writing: %m\n", path);
863 r = 1;
864 goto ERROR;
865 }
866
867 // Write configuration
868 size_t bytes_written = fprintf(f, "%s", config);
869 if (bytes_written < strlen(config)) {
870 ERROR(pakfire, "Could not write repository configuration: %m\n");
871 r = 1;
872 goto ERROR;
873 }
874
875 // Success
876 r = 0;
877
878ERROR:
879 if (f)
880 fclose(f);
881 if (config)
882 free(config);
883 pakfire_repo_unref(repo);
884
885 return r;
886}
887
ac4c607b 888PAKFIRE_EXPORT int pakfire_shell(struct pakfire* pakfire) {
48dc31f7 889 int r;
1a276007 890
48dc31f7
MT
891 // Setup build environment
892 r = pakfire_build_setup(pakfire);
893 if (r)
894 return r;
1a276007 895
22a0733e
MT
896 // Export local repository if running in interactive mode
897 r = pakfire_build_enable_repos(pakfire);
898 if (r)
899 return r;
900
48dc31f7 901 return pakfire_execute_shell(pakfire);
1a276007 902}
397371db
MT
903
904int pakfire_build_clean(struct pakfire* pakfire, int flags) {
905 struct pakfire_repo* local = NULL;
906 int r = 0;
907
908 // Fetch local repository
7ccac5e5 909 local = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL);
397371db 910 if (!local) {
7ccac5e5 911 ERROR(pakfire, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL);
397371db
MT
912 goto ERROR;
913 }
914
915 // Destroy everything in it
916 r = pakfire_repo_clean(local, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY);
917 if (r)
918 goto ERROR;
919
920ERROR:
921 if (local)
922 pakfire_repo_unref(local);
923
924 return r;
925}