]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/cli/lib/build.c
cli: Check for root privileges when needed
[people/ms/pakfire.git] / src / cli / lib / build.c
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/build.h>
32 #include <pakfire/pakfire.h>
33
34 #define MAX_MAKEFILES 32
35
36 struct config {
37 const char* id;
38 const char* target;
39 int flags;
40
41 // Makefiles
42 char* makefiles[MAX_MAKEFILES];
43 unsigned int num_makefiles;
44 };
45
46 enum {
47 OPT_DISABLE_CCACHE = 1,
48 OPT_DISABLE_SNAPSHOT = 2,
49 OPT_DISABLE_TESTS = 3,
50 OPT_ID = 4,
51 OPT_NON_INTERACTIVE = 5,
52 OPT_TARGET = 6,
53 };
54
55 static struct argp_option options[] = {
56 { "disable-ccache", OPT_DISABLE_CCACHE, NULL, 0, "Disable the ccache", 0 },
57 { "disable-snapshot", OPT_DISABLE_SNAPSHOT, NULL, 0, "Do not use the snapshot", 0 },
58 { "disable-tests", OPT_DISABLE_TESTS, NULL, 0, "Do not run tests", 0 },
59 { "id", OPT_ID, "ID", 0, "Use this build ID", 1 },
60 { "non-interactive", OPT_NON_INTERACTIVE, NULL, 0, "Run the build non-interactively", 0 },
61 { "target", OPT_TARGET, "TARGET", 0, "Output all packages into this directory", 0 },
62 { NULL },
63 };
64
65 static error_t parse(int key, char* arg, struct argp_state* state, void* data) {
66 struct config* config = data;
67
68 switch (key) {
69 case OPT_DISABLE_CCACHE:
70 config->flags |= PAKFIRE_BUILD_DISABLE_CCACHE;
71 break;
72
73 case OPT_DISABLE_SNAPSHOT:
74 config->flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
75 break;
76
77 case OPT_DISABLE_TESTS:
78 config->flags |= PAKFIRE_BUILD_DISABLE_TESTS;
79 break;
80
81 case OPT_ID:
82 config->id = arg;
83 break;
84
85 case OPT_NON_INTERACTIVE:
86 config->flags &= ~PAKFIRE_BUILD_INTERACTIVE;
87 break;
88
89 case OPT_TARGET:
90 config->target = arg;
91 break;
92
93 case ARGP_KEY_ARG:
94 if (config->num_makefiles >= MAX_MAKEFILES)
95 return -ENOBUFS;
96
97 config->makefiles[config->num_makefiles++] = arg;
98 break;
99
100 default:
101 return ARGP_ERR_UNKNOWN;
102 }
103
104 return 0;
105 }
106
107 static int log_callback(struct pakfire_build* build, void* data,
108 int priority, int error, const char* file, int line, const char* function, const char* format, ...) {
109 char* buffer = NULL;
110 va_list args;
111 int r;
112
113 // Format the message
114 va_start(args, format);
115 r = vasprintf(&buffer, format, args);
116 va_end(args);
117
118 // Fail if we could not format the message
119 if (r < 0)
120 return r;
121
122 switch (priority) {
123 // Highlight any error messages
124 case LOG_ERR:
125 fprintf(stderr, "%s%s%s", color_highlight(), buffer, color_reset());
126 break;
127
128 // Print the rest to stdout
129 default:
130 fprintf(stdout, "%s", buffer);
131 break;
132 }
133
134 // Cleanup
135 if (buffer)
136 free(buffer);
137
138 return 0;
139 }
140
141 int cli_build(void* data, int argc, char* argv[]) {
142 struct pakfire* pakfire = NULL;
143 struct pakfire_build* build = NULL;
144 struct config config = {
145 .id = NULL,
146 .target = NULL,
147 .flags = PAKFIRE_BUILD_INTERACTIVE,
148 };
149 int r;
150
151 struct cli_config* cli_config = data;
152
153 // Parse the command line
154 r = cli_parse(options, NULL, NULL, NULL, parse, 0, argc, argv, &config);
155 if (r)
156 goto ERROR;
157
158 // Setup pakfire
159 r = cli_setup_pakfire(&pakfire, cli_config);
160 if (r)
161 goto ERROR;
162
163 // Setup the build environment
164 r = pakfire_build_create(&build, pakfire, config.id, config.flags);
165 if (r) {
166 fprintf(stderr, "Could not setup the build environment: %m\n");
167 goto ERROR;
168 }
169
170 // Set log callback
171 pakfire_build_set_log_callback(build, log_callback, NULL);
172
173 // Set target
174 if (config.target) {
175 r = pakfire_build_set_target(build, config.target);
176 if (r) {
177 fprintf(stderr, "Could not set target directory %s: %m\n", config.target);
178 goto ERROR;
179 }
180 }
181
182 // Process all packages
183 for (unsigned int i = 0; i < config.num_makefiles; i++) {
184 // Run the build
185 r = pakfire_build_exec(build, config.makefiles[i]);
186 if (r) {
187 fprintf(stderr, "Could not build %s\n", config.makefiles[i]);
188 goto ERROR;
189 }
190 }
191
192 ERROR:
193 if (build)
194 pakfire_build_unref(build);
195 if (pakfire)
196 pakfire_unref(pakfire);
197
198 return r;
199 }