]> git.ipfire.org Git - pakfire.git/blame_incremental - src/cli/lib/build.c
cli: Show the repo description when listing repositories
[pakfire.git] / src / cli / lib / build.c
... / ...
CommitLineData
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2023 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 <argp.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <sys/syslog.h>
25
26#include "build.h"
27#include "color.h"
28#include "command.h"
29#include "pakfire.h"
30
31#include <pakfire/archive.h>
32#include <pakfire/build.h>
33#include <pakfire/log_file.h>
34#include <pakfire/package.h>
35#include <pakfire/root.h>
36#include <pakfire/path.h>
37#include <pakfire/repo.h>
38
39#define MAX_MAKEFILES 32
40
41struct cli_local_args {
42 const char* distro;
43 const char* target;
44 enum {
45 BUILD_INTERACTIVE = (1 << 0),
46 BUILD_ENABLE_CCACHE = (1 << 1),
47 BUILD_ENABLE_SNAPSHOT = (1 << 2),
48 BUILD_ENABLE_TESTS = (1 << 3),
49 } flags;
50
51 // Log file
52 pakfire_log_file* log_file;
53 const char* log_path;
54
55 // Makefiles
56 char* makefiles[MAX_MAKEFILES];
57 unsigned int num_makefiles;
58};
59
60enum {
61 OPT_DISABLE_CCACHE = 1,
62 OPT_DISABLE_SNAPSHOT = 2,
63 OPT_DISABLE_TESTS = 3,
64 OPT_LOG_FILE = 4,
65 OPT_NON_INTERACTIVE = 5,
66 OPT_TARGET = 6,
67};
68
69static struct argp_option options[] = {
70 { "disable-ccache", OPT_DISABLE_CCACHE, NULL, 0, "Disable the ccache", 0 },
71 { "disable-snapshot", OPT_DISABLE_SNAPSHOT, NULL, 0, "Do not use the snapshot", 0 },
72 { "disable-tests", OPT_DISABLE_TESTS, NULL, 0, "Do not run tests", 0 },
73 { "log-file", OPT_LOG_FILE, "PATH", 0, "Writes the log to a file", 0 },
74 { "non-interactive", OPT_NON_INTERACTIVE, NULL, 0, "Run the build non-interactively", 0 },
75 { "target", OPT_TARGET, "TARGET", 0, "Output all packages into this directory", 0 },
76 { NULL },
77};
78
79static error_t parse(int key, char* arg, struct argp_state* state, void* data) {
80 struct cli_local_args* args = data;
81
82 switch (key) {
83 case OPT_DISABLE_CCACHE:
84 args->flags &= ~BUILD_ENABLE_CCACHE;
85 break;
86
87 case OPT_DISABLE_SNAPSHOT:
88 args->flags &= ~BUILD_ENABLE_SNAPSHOT;
89 break;
90
91 case OPT_DISABLE_TESTS:
92 args->flags &= ~BUILD_ENABLE_TESTS;
93 break;
94
95 case OPT_LOG_FILE:
96 args->log_path = arg;
97 break;
98
99 case OPT_NON_INTERACTIVE:
100 args->flags &= ~BUILD_INTERACTIVE;
101 break;
102
103 case OPT_TARGET:
104 args->target = arg;
105 break;
106
107 case ARGP_KEY_ARG:
108 if (args->num_makefiles >= MAX_MAKEFILES)
109 return -ENOBUFS;
110
111 args->makefiles[args->num_makefiles++] = arg;
112 break;
113
114 default:
115 return ARGP_ERR_UNKNOWN;
116 }
117
118 return 0;
119}
120
121static void log_callback(void* data, int priority, const char* file, int line,
122 const char* function, const char* format, va_list args)
123 __attribute__((format(printf, 6, 0)));
124
125static void log_callback(void* data, int priority, const char* file, int line,
126 const char* function, const char* format, va_list args) {
127 const struct cli_local_args* local_args = data;
128 char* buffer = NULL;
129 ssize_t length;
130
131 // Format the line
132 length = vasprintf(&buffer, format, args);
133 if (length < 0)
134 return;
135
136 switch (priority) {
137 // Highlight any warnings
138 case LOG_WARNING:
139 fputs(color_yellow(), stderr);
140 fprintf(stderr, "%s", buffer);
141 fputs(color_reset(), stderr);
142 break;
143
144 // Highlight any error messages
145 case LOG_ERR:
146 fputs(color_highlight(), stderr);
147 fprintf(stderr, "%s", buffer);
148 fputs(color_reset(), stderr);
149 break;
150
151 // Print anything to standard output
152 default:
153 fprintf(stdout, "%s", buffer);
154 break;
155 }
156
157 // Write to the log file
158 if (local_args->log_file)
159 pakfire_log_file_write(local_args->log_file, priority, buffer, length);
160
161 if (buffer)
162 free(buffer);
163}
164
165static int result_callback(pakfire_ctx* ctx, pakfire_root* root,
166 pakfire_build* build, pakfire_archive* archive, void* data) {
167 const struct cli_local_args* local_args = data;
168 pakfire_package* pkg = NULL;
169 pakfire_repo* local = NULL;
170 char path[PATH_MAX];
171 int r;
172
173 // Fetch the package metadata
174 r = pakfire_archive_make_package(archive, NULL, &pkg);
175 if (r < 0)
176 goto ERROR;
177
178 // Fetch NEVRA
179 const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA);
180
181 // Fetch the local repository & import the archive
182 local = pakfire_root_get_repo(root, PAKFIRE_REPO_LOCAL);
183 if (local) {
184 r = pakfire_repo_import_archive(local, archive, NULL);
185 if (r < 0) {
186 ERROR(ctx, "Could not import %s to the local repository: %s\n",
187 nevra, strerror(-r));
188 goto ERROR;
189 }
190 }
191
192 // Copy to the target (if given)
193 if (local_args->target) {
194 // Fetch the filename
195 const char* filename = pakfire_package_get_filename(pkg);
196
197 // Make the absolute target path
198 r = pakfire_path_append(path, local_args->target, filename);
199 if (r < 0)
200 goto ERROR;
201
202 // Copy (or link) the package to the target path
203 r = pakfire_archive_link_or_copy(archive, path);
204 if (r < 0) {
205 ERROR(ctx, "Could not copy %s to %s: %s\n",
206 nevra, path, strerror(-r));
207 goto ERROR;
208 }
209 }
210
211ERROR:
212 if (local)
213 pakfire_repo_unref(local);
214 if (pkg)
215 pakfire_package_unref(pkg);
216
217 return r;
218}
219
220int cli_build(void* data, int argc, char* argv[]) {
221 struct cli_global_args* global_args = data;
222 struct cli_local_args local_args = {
223 .flags =
224 BUILD_INTERACTIVE |
225 BUILD_ENABLE_CCACHE |
226 BUILD_ENABLE_SNAPSHOT |
227 BUILD_ENABLE_TESTS,
228 };
229 pakfire_build* build = NULL;
230 int flags = PAKFIRE_BUILD_LOCAL;
231 int r;
232
233 // Parse the command line
234 r = cli_parse(options, NULL, NULL, NULL, parse, 0, argc, argv, &local_args);
235 if (r)
236 goto ERROR;
237
238 // Replace the logger
239 pakfire_ctx_set_log_callback(global_args->ctx, log_callback, &local_args);
240
241 // Use the snapshot?
242 if (local_args.flags & BUILD_ENABLE_SNAPSHOT)
243 flags |= PAKFIRE_BUILD_ENABLE_SNAPSHOT;
244
245 // Is the build interactive?
246 if (local_args.flags & BUILD_INTERACTIVE)
247 flags |= PAKFIRE_BUILD_INTERACTIVE;
248
249 // Enable ccache?
250 if (!(local_args.flags & BUILD_ENABLE_CCACHE))
251 flags |= PAKFIRE_BUILD_DISABLE_CCACHE;
252
253 // Enable tests?
254 if (!(local_args.flags & BUILD_ENABLE_TESTS))
255 flags |= PAKFIRE_BUILD_DISABLE_TESTS;
256
257 // Create the log file
258 if (local_args.log_path) {
259 r = pakfire_log_file_create(&local_args.log_file,
260 global_args->ctx, local_args.log_path, NULL, 0);
261 if (r < 0)
262 goto ERROR;
263 }
264
265 // Setup the build environment
266 r = cli_setup_build(&build, global_args, flags);
267 if (r < 0)
268 goto ERROR;
269
270 // Process all packages
271 for (unsigned int i = 0; i < local_args.num_makefiles; i++) {
272 // Run the build
273 r = pakfire_build_exec(build, local_args.makefiles[i], result_callback, &local_args);
274 if (r) {
275 fprintf(stderr, "Could not build %s\n", local_args.makefiles[i]);
276 goto ERROR;
277 }
278 }
279
280ERROR:
281 if (local_args.log_file)
282 pakfire_log_file_unref(local_args.log_file);
283 if (build)
284 pakfire_build_unref(build);
285
286 return r;
287}