]> git.ipfire.org Git - pakfire.git/commitdiff
client: Implement create builds from the CLI
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 26 Jun 2025 16:58:30 +0000 (16:58 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 26 Jun 2025 16:58:30 +0000 (16:58 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/cli/lib/client-build.c
src/pakfire/client.c
src/pakfire/client.h

index c21c73c093ffe855210954e80634491fe2c19b71..6fff2cbec42a4547266a09b4a2e2a8f06ded9bff 100644 (file)
@@ -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);
 
index dab66c8fe49211b61c0a40b8ce7f872c269b111f..05f352582080bfa544600eef4b15c3b48a68a773 100644 (file)
@@ -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;
 }
 
index b19346d2b5591378ed2e545eb7a6600c073d8e67..a977da2a899ecb45c4139a952da8d6f2dbaa9609 100644 (file)
@@ -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