]>
Commit | Line | Data |
---|---|---|
060a1182 MT |
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 | ||
ee8a3a64 | 21 | #include <argp.h> |
060a1182 | 22 | #include <errno.h> |
060a1182 | 23 | #include <stdlib.h> |
6bda496c | 24 | #include <sys/syslog.h> |
060a1182 MT |
25 | |
26 | #include "build.h" | |
6bda496c | 27 | #include "color.h" |
060a1182 | 28 | #include "command.h" |
ee8a3a64 | 29 | #include "pakfire.h" |
060a1182 | 30 | |
3c486a7f | 31 | #include <pakfire/archive.h> |
060a1182 | 32 | #include <pakfire/build.h> |
18ac96e3 | 33 | #include <pakfire/log_file.h> |
3c486a7f | 34 | #include <pakfire/package.h> |
e0ad83d5 | 35 | #include <pakfire/root.h> |
3c486a7f MT |
36 | #include <pakfire/path.h> |
37 | #include <pakfire/repo.h> | |
060a1182 | 38 | |
ee8a3a64 MT |
39 | #define MAX_MAKEFILES 32 |
40 | ||
343d9736 | 41 | struct cli_local_args { |
90566df0 | 42 | const char* distro; |
060a1182 | 43 | const char* target; |
842bd2ba MT |
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; | |
ee8a3a64 | 50 | |
18ac96e3 | 51 | // Log file |
bd7d97a7 | 52 | pakfire_log_file* log_file; |
18ac96e3 MT |
53 | const char* log_path; |
54 | ||
ee8a3a64 MT |
55 | // Makefiles |
56 | char* makefiles[MAX_MAKEFILES]; | |
57 | unsigned int num_makefiles; | |
060a1182 MT |
58 | }; |
59 | ||
ee8a3a64 | 60 | enum { |
24e9c0e0 MT |
61 | OPT_DISABLE_CCACHE = 1, |
62 | OPT_DISABLE_SNAPSHOT = 2, | |
63 | OPT_DISABLE_TESTS = 3, | |
18ac96e3 MT |
64 | OPT_LOG_FILE = 4, |
65 | OPT_NON_INTERACTIVE = 5, | |
66 | OPT_TARGET = 6, | |
ee8a3a64 | 67 | }; |
060a1182 | 68 | |
ee8a3a64 MT |
69 | static 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 }, | |
18ac96e3 | 73 | { "log-file", OPT_LOG_FILE, "PATH", 0, "Writes the log to a file", 0 }, |
ee8a3a64 MT |
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 | }; | |
060a1182 | 78 | |
d673ca6c | 79 | static error_t parse(int key, char* arg, struct argp_state* state, void* data) { |
343d9736 | 80 | struct cli_local_args* args = data; |
060a1182 | 81 | |
ee8a3a64 MT |
82 | switch (key) { |
83 | case OPT_DISABLE_CCACHE: | |
343d9736 | 84 | args->flags &= ~BUILD_ENABLE_CCACHE; |
060a1182 MT |
85 | break; |
86 | ||
ee8a3a64 | 87 | case OPT_DISABLE_SNAPSHOT: |
343d9736 | 88 | args->flags &= ~BUILD_ENABLE_SNAPSHOT; |
ee8a3a64 | 89 | break; |
060a1182 | 90 | |
ee8a3a64 | 91 | case OPT_DISABLE_TESTS: |
343d9736 | 92 | args->flags &= ~BUILD_ENABLE_TESTS; |
ee8a3a64 | 93 | break; |
060a1182 | 94 | |
18ac96e3 MT |
95 | case OPT_LOG_FILE: |
96 | args->log_path = arg; | |
97 | break; | |
98 | ||
ee8a3a64 | 99 | case OPT_NON_INTERACTIVE: |
343d9736 | 100 | args->flags &= ~BUILD_INTERACTIVE; |
ee8a3a64 | 101 | break; |
060a1182 | 102 | |
ee8a3a64 | 103 | case OPT_TARGET: |
343d9736 | 104 | args->target = arg; |
ee8a3a64 | 105 | break; |
060a1182 | 106 | |
ee8a3a64 | 107 | case ARGP_KEY_ARG: |
343d9736 | 108 | if (args->num_makefiles >= MAX_MAKEFILES) |
ee8a3a64 | 109 | return -ENOBUFS; |
060a1182 | 110 | |
343d9736 | 111 | args->makefiles[args->num_makefiles++] = arg; |
ee8a3a64 | 112 | break; |
060a1182 | 113 | |
ee8a3a64 MT |
114 | default: |
115 | return ARGP_ERR_UNKNOWN; | |
060a1182 MT |
116 | } |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
d5b92ec9 MT |
121 | static 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 | ||
e0e57930 MT |
125 | static void log_callback(void* data, int priority, const char* file, int line, |
126 | const char* function, const char* format, va_list args) { | |
18ac96e3 MT |
127 | const struct cli_local_args* local_args = data; |
128 | char* buffer = NULL; | |
129 | ssize_t length; | |
18ac96e3 MT |
130 | |
131 | // Format the line | |
132 | length = vasprintf(&buffer, format, args); | |
133 | if (length < 0) | |
134 | return; | |
dc173159 | 135 | |
6bda496c | 136 | switch (priority) { |
1ac9f900 MT |
137 | // Highlight any warnings |
138 | case LOG_WARNING: | |
139 | fputs(color_yellow(), stderr); | |
18ac96e3 | 140 | fprintf(stderr, "%s", buffer); |
1ac9f900 MT |
141 | fputs(color_reset(), stderr); |
142 | break; | |
143 | ||
bde60bc5 MT |
144 | // Highlight any error messages |
145 | case LOG_ERR: | |
146 | fputs(color_highlight(), stderr); | |
18ac96e3 | 147 | fprintf(stderr, "%s", buffer); |
bde60bc5 | 148 | fputs(color_reset(), stderr); |
6bda496c | 149 | break; |
cba07c0a MT |
150 | |
151 | // Print anything to standard output | |
152 | default: | |
153 | fprintf(stdout, "%s", buffer); | |
154 | break; | |
6bda496c MT |
155 | } |
156 | ||
18ac96e3 MT |
157 | // Write to the log file |
158 | if (local_args->log_file) | |
fe878bea | 159 | pakfire_log_file_write(local_args->log_file, priority, buffer, length); |
18ac96e3 MT |
160 | |
161 | if (buffer) | |
162 | free(buffer); | |
6bda496c MT |
163 | } |
164 | ||
c87e1399 | 165 | static int result_callback(pakfire_ctx* ctx, pakfire_root* root, |
0ecfa7b1 | 166 | pakfire_build* build, pakfire_archive* archive, void* data) { |
3c486a7f | 167 | const struct cli_local_args* local_args = data; |
c4d26cd6 | 168 | pakfire_package* pkg = NULL; |
21d186ba | 169 | pakfire_repo* local = NULL; |
3c486a7f MT |
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 | |
c87e1399 | 182 | local = pakfire_root_get_repo(root, PAKFIRE_REPO_LOCAL); |
3c486a7f | 183 | if (local) { |
84337f75 | 184 | r = pakfire_repo_import_archive(local, archive, NULL); |
3c486a7f MT |
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 | ||
211 | ERROR: | |
212 | if (local) | |
213 | pakfire_repo_unref(local); | |
214 | if (pkg) | |
215 | pakfire_package_unref(pkg); | |
216 | ||
217 | return r; | |
218 | } | |
219 | ||
ee8a3a64 | 220 | int cli_build(void* data, int argc, char* argv[]) { |
343d9736 MT |
221 | struct cli_global_args* global_args = data; |
222 | struct cli_local_args local_args = { | |
842bd2ba MT |
223 | .flags = |
224 | BUILD_INTERACTIVE | | |
225 | BUILD_ENABLE_CCACHE | | |
226 | BUILD_ENABLE_SNAPSHOT | | |
227 | BUILD_ENABLE_TESTS, | |
060a1182 | 228 | }; |
0ecfa7b1 | 229 | pakfire_build* build = NULL; |
6e68f7a8 | 230 | int flags = PAKFIRE_BUILD_LOCAL; |
060a1182 MT |
231 | int r; |
232 | ||
ee8a3a64 | 233 | // Parse the command line |
343d9736 | 234 | r = cli_parse(options, NULL, NULL, NULL, parse, 0, argc, argv, &local_args); |
060a1182 | 235 | if (r) |
ee8a3a64 MT |
236 | goto ERROR; |
237 | ||
e0e57930 | 238 | // Replace the logger |
18ac96e3 | 239 | pakfire_ctx_set_log_callback(global_args->ctx, log_callback, &local_args); |
e0e57930 | 240 | |
eccc1d5b | 241 | // Use the snapshot? |
343d9736 | 242 | if (local_args.flags & BUILD_ENABLE_SNAPSHOT) |
d8751c8d | 243 | flags |= PAKFIRE_BUILD_ENABLE_SNAPSHOT; |
060a1182 | 244 | |
842bd2ba | 245 | // Is the build interactive? |
343d9736 | 246 | if (local_args.flags & BUILD_INTERACTIVE) |
2a81deb4 | 247 | flags |= PAKFIRE_BUILD_INTERACTIVE; |
842bd2ba MT |
248 | |
249 | // Enable ccache? | |
343d9736 | 250 | if (!(local_args.flags & BUILD_ENABLE_CCACHE)) |
d8751c8d | 251 | flags |= PAKFIRE_BUILD_DISABLE_CCACHE; |
842bd2ba MT |
252 | |
253 | // Enable tests? | |
343d9736 | 254 | if (!(local_args.flags & BUILD_ENABLE_TESTS)) |
d8751c8d | 255 | flags |= PAKFIRE_BUILD_DISABLE_TESTS; |
90566df0 | 256 | |
18ac96e3 MT |
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 | ||
060a1182 | 265 | // Setup the build environment |
d8751c8d MT |
266 | r = cli_setup_build(&build, global_args, flags); |
267 | if (r < 0) | |
060a1182 | 268 | goto ERROR; |
060a1182 | 269 | |
060a1182 | 270 | // Process all packages |
343d9736 | 271 | for (unsigned int i = 0; i < local_args.num_makefiles; i++) { |
060a1182 | 272 | // Run the build |
3c486a7f | 273 | r = pakfire_build_exec(build, local_args.makefiles[i], result_callback, &local_args); |
060a1182 | 274 | if (r) { |
343d9736 | 275 | fprintf(stderr, "Could not build %s\n", local_args.makefiles[i]); |
060a1182 MT |
276 | goto ERROR; |
277 | } | |
278 | } | |
279 | ||
280 | ERROR: | |
18ac96e3 MT |
281 | if (local_args.log_file) |
282 | pakfire_log_file_unref(local_args.log_file); | |
060a1182 MT |
283 | if (build) |
284 | pakfire_build_unref(build); | |
285 | ||
286 | return r; | |
287 | } |