From: Michael Tremer Date: Thu, 26 Jun 2025 16:58:30 +0000 (+0000) Subject: client: Implement create builds from the CLI X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6fafce68a76918a09a2354787120db4620e881a2;p=pakfire.git client: Implement create builds from the CLI Signed-off-by: Michael Tremer --- diff --git a/src/cli/lib/client-build.c b/src/cli/lib/client-build.c index c21c73c0..6fff2cbe 100644 --- a/src/cli/lib/client-build.c +++ b/src/cli/lib/client-build.c @@ -39,16 +39,15 @@ struct cli_local_args { const char* repo; int flags; + // Exit Status + int status; + const char* arches[MAX_ARCHES]; unsigned int num_arches; // Packages char* packages[MAX_PACKAGES]; unsigned int num_packages; - - // Uploads - char* uploads[MAX_UPLOADS]; - unsigned int num_uploads; }; enum { @@ -97,11 +96,76 @@ static error_t parse(int key, char* arg, struct argp_state* state, void* data) { return 0; } +static int build_callback(struct pakfire_client* client, int status, const char* uuid, void* data) { + struct cli_local_args* local_args = data; + + // Was there an error? + if (status) { + // Store the status + local_args->status = status; + + // XXX Can we add any useful information which package it was and what the reason was? + fprintf(stderr, "Failed to create build\n"); + + return 0; + } + + // XXX Here, we should actually send another API request that fetches the entire build object + // or change the callback so that we receive the raw (parsed) JSON objects. + + // Show status + printf("Created build %s\n", uuid); + + return 0; +} + +// Called when an upload was successful +static int upload_callback(struct pakfire_client* client, + pakfire_client_upload_status status, const char* path, const char* uuid, void* data) { + struct cli_local_args* local_args = data; + int r; + + // Create the build + r = pakfire_client_build(client, uuid, local_args->repo, + local_args->arches, local_args->flags, build_callback, local_args); + if (r < 0) { + fprintf(stderr, "Failed to create build from %s: %s\n", path, strerror(-r)); + + // Store the status + local_args->status = r; + return r; + } + + return 0; +} + +static int ready_callback(struct pakfire_client* client, void* data) { + struct cli_local_args* local_args = data; + int r; + + // XXX Should we check if the repository exists? + + // Upload all packages + for (unsigned int i = 0; i < local_args->num_packages; i++) { + r = pakfire_client_upload(client, local_args->packages[i], NULL, + upload_callback, local_args); + if (r < 0) { + fprintf(stderr, "Failed to create upload %s: %s\n", + local_args->packages[i], strerror(-r)); + + // Store the status + local_args->status = r; + return r; + } + } + + return 0; +} + int cli_client_build(void* data, int argc, char* argv[]) { struct cli_global_args* global_args = data; struct cli_local_args local_args = {}; struct pakfire_client* client = NULL; - char* upload = NULL; int r; // Parse the command line @@ -114,42 +178,18 @@ int cli_client_build(void* data, int argc, char* argv[]) { if (r < 0) goto ERROR; -#if 0 - // Upload all packages - for (unsigned int i = 0; i < local_args.num_packages; i++) { - r = pakfire_client_upload(client, local_args.packages[i], NULL, &upload); - if (r) - goto ERROR; + // Set ready callback + pakfire_client_set_ready_callback(client, ready_callback, &local_args); - // Store the upload ID - local_args.uploads[local_args.num_uploads++] = upload; - } -#endif - - // No uploads - if (!local_args.num_uploads) + // Run the client + r = pakfire_client_run(client); + if (r < 0) goto ERROR; - // Build all the things - for (unsigned int i = 0; i < local_args.num_uploads; i++) { - r = pakfire_client_build(client, local_args.uploads[i], local_args.repo, - local_args.arches, local_args.flags); - if (r) - goto ERROR; - - // Free the upload - free(local_args.uploads[i]); - local_args.uploads[i] = NULL; - } + // Return the status + r = local_args.status; ERROR: - // Delete & free all uploads that could not be processed - for (unsigned int i = 0; i < local_args.num_uploads; i++) { - if (local_args.uploads[i]) { - pakfire_client_delete_upload(client, local_args.uploads[i]); - free(local_args.uploads[i]); - } - } if (client) pakfire_client_unref(client); diff --git a/src/pakfire/client.c b/src/pakfire/client.c index dab66c8f..05f35258 100644 --- a/src/pakfire/client.c +++ b/src/pakfire/client.c @@ -847,20 +847,86 @@ int pakfire_client_builder_disconnected(struct pakfire_client* self, struct pakf // Build -int pakfire_client_build(struct pakfire_client* self, const char* upload, - const char* repo, const char** arches, int flags) { +struct pakfire_client_build { + // Client + struct pakfire_client* client; + + // Callback + pakfire_client_build_callback callback; + void* data; +}; + +static int pakfire_client_build_create(struct pakfire_client_build** build, + struct pakfire_client* client) { + struct pakfire_client_build* self = NULL; + + // Allocate a new object + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Store a reference to the client + self->client = pakfire_client_ref(client); + + // Return the pointer + *build = self; + + return 0; +} + +static void pakfire_client_build_free(struct pakfire_client_build* self) { + if (self->client) + pakfire_client_unref(self->client); + free(self); +} + +static int pakfire_client_build_response(struct pakfire_xfer* xfer, + pakfire_xfer_error_code_t status, struct json_object* response, void* data) { + struct pakfire_client_build* build = data; + const char* uuid = NULL; + int r = 0; + + // Only process this if we have a callback + if (build->callback) { + // Extract the UUID from the response + r = pakfire_json_get_string(response, "uuid", &uuid); + if (r < 0) + goto ERROR; + + // Call the callback + r = build->callback(build->client, status, uuid, build->data); + } + +ERROR: + pakfire_client_build_free(build); + + return r; +} + +int pakfire_client_build(struct pakfire_client* self, const char* upload, const char* repo, + const char** arches, int flags, pakfire_client_build_callback callback, void* data) { + struct pakfire_client_build* build = NULL; struct pakfire_xfer* xfer = NULL; struct json_object* request = NULL; int r; + // Create a new build object + r = pakfire_client_build_create(&build, self); + if (r < 0) + goto ERROR; + + // Store the callback + build->callback = callback; + build->data = data; + // Create a new xfer r = pakfire_client_xfer_create(&xfer, self, "/api/v1/builds"); - if (r) + if (r < 0) goto ERROR; // Enable authentication r = pakfire_client_xfer_auth(self, xfer); - if (r) + if (r < 0) goto ERROR; // Create a new request object @@ -893,8 +959,18 @@ int pakfire_client_build(struct pakfire_client* self, const char* upload, if (r < 0) goto ERROR; - // Send the request - r = pakfire_xfer_run_api_request(xfer, request, NULL); + // Set the request body + r = pakfire_xfer_set_json_payload(xfer, request); + if (r < 0) + goto ERROR; + + // Register the callback + r = pakfire_xfer_set_response_callback(xfer, pakfire_client_build_response, build); + if (r < 0) + goto ERROR; + + // Enqueue the transfer + r = pakfire_httpclient_enqueue(self->httpclient, xfer); if (r < 0) goto ERROR; @@ -902,6 +978,10 @@ ERROR: if (xfer) pakfire_xfer_unref(xfer); + // Remove the build on error + if (r && build) + pakfire_client_build_free(build); + return r; } diff --git a/src/pakfire/client.h b/src/pakfire/client.h index b19346d2..a977da2a 100644 --- a/src/pakfire/client.h +++ b/src/pakfire/client.h @@ -76,8 +76,11 @@ typedef enum pakfire_client_build_flags { PAKFIRE_CLIENT_DISABLE_TESTS = (1 << 0), } pakfire_client_build_flags_t; -int pakfire_client_build(struct pakfire_client* client, const char* upload, - const char* repo, const char** arches, int flags); +typedef int (*pakfire_client_build_callback) + (struct pakfire_client* client, int status, const char* uuid, void* data); + +int pakfire_client_build(struct pakfire_client* client, const char* upload, const char* repo, + const char** arches, int flags, pakfire_client_build_callback callback, void* data); // Uploads