]>
Commit | Line | Data |
---|---|---|
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 | ||
34 | static 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 |
52 | static 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 | ||
94 | ERROR: | |
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 | ||
105 | static 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 | ||
134 | ERROR: | |
135 | if (packages) | |
136 | free(packages); | |
137 | ||
138 | return r; | |
139 | } | |
140 | ||
7d999600 MT |
141 | static 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 | ||
166 | ERROR: | |
167 | if (script) | |
168 | free(script); | |
169 | ||
170 | return r; | |
171 | } | |
172 | ||
173 | PAKFIRE_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 | |
213 | ERROR: | |
214 | if (makefile) | |
215 | pakfire_parser_unref(makefile); | |
216 | ||
217 | return r; | |
218 | } | |
219 | ||
220 | PAKFIRE_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 | } |