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