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