]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/build.c
parser: Unify fetching declarations and implement template lookaside
[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>
22#include <stdlib.h>
23
24#include <pakfire/build.h>
25#include <pakfire/execute.h>
26#include <pakfire/dist.h>
27#include <pakfire/logging.h>
28#include <pakfire/parser.h>
29#include <pakfire/private.h>
30#include <pakfire/types.h>
31#include <pakfire/util.h>
32
33static const char* stages[] = {
34 "prepare",
35 "build",
36 "test",
37 "install",
38 NULL,
39};
40
41#define TEMPLATE \
42 "#!/bin/bash --login\n" \
43 "\n" \
44 "set -e\n" \
45 "set -x\n" \
46 "\n" \
47 "%%{_%s}\n" \
48 "\n" \
49 "exit 0\n"
50
a50bde9c
MT
51static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile, const char* handle) {
52 int r = 1;
53
54 // Expand the handle into the package name
55 char* name = pakfire_parser_expand(makefile, "packages", handle);
56 if (!name) {
57 ERROR(pakfire, "Could not get package name: %s\n", strerror(errno));
58 goto ERROR;
59 }
60
61 INFO(pakfire, "Building package '%s'...\n", name);
62
63 // XXX actually do all the work
64
65 // Success
66 r = 0;
67
68ERROR:
69 if (name)
70 free(name);
71
72 return r;
73}
74
75static int pakfire_build_packages(Pakfire pakfire, PakfireParser makefile) {
76 DEBUG(pakfire, "Creating packages...");
77 int r = 1;
78
79 // Fetch a list all all packages
80 char** packages = pakfire_parser_list_namespaces(makefile, "packages.package:*");
81 if (!packages) {
82 ERROR(pakfire, "Could not find any packages: %s\n", strerror(errno));
83 goto ERROR;
84 }
85
86 unsigned int num_packages = 0;
87
88 // Count how many packages we have
89 for (char** package = packages; *package; package++)
90 num_packages++;
91
92 DEBUG(pakfire, "Found %d package(s)\n", num_packages);
93
94 // Build packages in reverse order
95 for (int i = num_packages - 1; i >= 0; i--) {
96 r = pakfire_build_package(pakfire, makefile,
97 packages[i] + strlen("packages.package:"));
98 if (r)
99 goto ERROR;
100 }
101
102 // Success
103 r = 0;
104
105ERROR:
106 if (packages)
107 free(packages);
108
109 return r;
110}
111
7d999600
MT
112static int pakfire_build_stage(Pakfire pakfire, PakfireParser makefile, const char* stage,
113 pakfire_execute_logging_callback logging_callback, void* data) {
1a276007
MT
114 char template[1024];
115
116 // Prepare template for this stage
117 int r = pakfire_string_format(template, TEMPLATE, stage);
118 if (r < 0)
119 return r;
120
121 // Create the build script
122 char* script = pakfire_parser_expand(makefile, "build", template);
123 if (!script) {
124 ERROR(pakfire, "Could not generate the build script for stage '%s': %s\n",
125 stage, strerror(errno));
126 goto ERROR;
127 }
128
129 INFO(pakfire, "Running build stage '%s'\n", stage);
130
7d999600
MT
131 r = pakfire_execute_script(pakfire, script, strlen(script), NULL, 0,
132 logging_callback, data);
1a276007
MT
133 if (r) {
134 ERROR(pakfire, "Build stage '%s' failed with status %d\n", stage, r);
135 }
136
137ERROR:
138 if (script)
139 free(script);
140
141 return r;
142}
143
144PAKFIRE_EXPORT int pakfire_build(Pakfire pakfire, const char* path,
7d999600
MT
145 const char* target, int flags,
146 pakfire_execute_logging_callback logging_callback, void* data) {
1a276007
MT
147 PakfireParser makefile = NULL;
148 struct pakfire_parser_error* error = NULL;
149
150 // Read makefile
151 int r = pakfire_read_makefile(&makefile, pakfire, path, &error);
152 if (r) {
153 if (error) {
154 ERROR(pakfire, "Could not parse makefile %s: %s\n", path,
155 pakfire_parser_error_get_message(error));
156 pakfire_parser_error_unref(error);
157 } else {
158 ERROR(pakfire, "Could not parse makefile %s: %s\n", path,
159 strerror(errno));
160 }
161
162 goto ERROR;
163 }
164
165 // Run through all build stages
166 for (const char** stage = stages; *stage; stage++) {
7d999600 167 int r = pakfire_build_stage(pakfire, makefile, *stage, logging_callback, data);
1a276007
MT
168 if (r) {
169 // Drop to a shell for debugging
170 if (flags & PAKFIRE_BUILD_INTERACTIVE)
171 pakfire_shell(pakfire);
172
173 goto ERROR;
174 }
175 }
176
a50bde9c
MT
177 // Create the packages
178 r = pakfire_build_packages(pakfire, makefile);
179 if (r) {
180 ERROR(pakfire, "Could not create packages: %s\n", strerror(errno));
181 goto ERROR;
182 }
1a276007
MT
183
184ERROR:
185 if (makefile)
186 pakfire_parser_unref(makefile);
187
188 return r;
189}
190
191PAKFIRE_EXPORT int pakfire_shell(Pakfire pakfire) {
192 const char* argv[] = {
193 "/bin/bash", "--login", NULL,
194 };
195
196 const int flags =
197 PAKFIRE_EXECUTE_INTERACTIVE | PAKFIRE_EXECUTE_ENABLE_NETWORK;
198
199 return pakfire_execute(pakfire, argv, NULL, flags, NULL, NULL);
200}