From: Michael Tremer Date: Thu, 19 Oct 2023 19:42:36 +0000 (+0000) Subject: buildservice: Implement uploading files X-Git-Tag: 0.9.30~1441 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0184033528d5dd5f95ac54b397c4096e1026cf69;p=pakfire.git buildservice: Implement uploading files Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 5a51c1c6b..4fd8f80cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -511,6 +511,8 @@ libcli_la_SOURCES = \ src/cli/lib/update.h \ src/cli/lib/upload.c \ src/cli/lib/upload.h \ + src/cli/lib/upload_create.c \ + src/cli/lib/upload_create.h \ src/cli/lib/upload_list.c \ src/cli/lib/upload_list.h \ src/cli/lib/version.c \ diff --git a/src/cli/lib/upload.c b/src/cli/lib/upload.c index 6ef733cf0..1396dc4ae 100644 --- a/src/cli/lib/upload.c +++ b/src/cli/lib/upload.c @@ -20,14 +20,17 @@ #include "command.h" #include "upload.h" +#include "upload_create.h" #include "upload_list.h" static const char* args_doc = + "create PATH\n" "list"; int cli_upload(void* data, int argc, char* argv[]) { static const struct command commands[] = { - { "list", cli_upload_list, 0, 0, 0 }, + { "create", cli_upload_create, 1, -1, 0 }, + { "list", cli_upload_list, 0, 0, 0 }, { NULL }, }; diff --git a/src/cli/lib/upload_create.c b/src/cli/lib/upload_create.c new file mode 100644 index 000000000..fc0309b3a --- /dev/null +++ b/src/cli/lib/upload_create.c @@ -0,0 +1,87 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2023 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include +#include + +#include "command.h" +#include "upload_create.h" + +static const char* args_doc = "FILES..."; + +static const char* doc = "Uploads a file"; + +#define MAX_FILES 32 + +struct config { + const char* files[MAX_FILES]; + unsigned int num_files; +}; + +static error_t parse(int key, char* arg, void* data) { + struct config* config = data; + + switch (key) { + case ARGP_KEY_ARG: + if (config->num_files >= MAX_FILES) + return -ENOBUFS; + + config->files[config->num_files++] = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +int cli_upload_create(void* data, int argc, char* argv[]) { + struct pakfire_buildservice* service = NULL; + struct config config = {}; + int r; + + struct pakfire_ctx* ctx = data; + + // Parse the command line + r = cli_parse(NULL, NULL, args_doc, doc, parse, argc, argv, &config); + if (r) + goto ERROR; + + // Connect to the build service + r = pakfire_buildservice_create(&service, ctx); + if (r) + goto ERROR; + + // List uploads + for (unsigned int i = 0; i < config.num_files; i++) { + r = pakfire_buildservice_upload(service, config.files[i], NULL); + if (r) + goto ERROR; + } + +ERROR: + if (service) + pakfire_buildservice_unref(service); + + return r; +} diff --git a/src/cli/lib/upload_create.h b/src/cli/lib/upload_create.h new file mode 100644 index 000000000..df0cc4c1b --- /dev/null +++ b/src/cli/lib/upload_create.h @@ -0,0 +1,26 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2023 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_CLI_UPLOAD_CREATE_H +#define PAKFIRE_CLI_UPLOAD_CREATE_H + +int cli_upload_create(void* data, int argc, char* argv[]); + +#endif /* PAKFIRE_CLI_UPLOAD_CREATE_H */ diff --git a/src/libpakfire/buildservice.c b/src/libpakfire/buildservice.c index 950e451cd..f2643fa7e 100644 --- a/src/libpakfire/buildservice.c +++ b/src/libpakfire/buildservice.c @@ -27,8 +27,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -208,6 +210,210 @@ ERROR: // Uploads +static int pakfire_buildservice_create_upload(struct pakfire_buildservice* service, + const char* path, const char* filename, FILE* f, char** uuid) { + struct pakfire_transfer* transfer = NULL; + struct json_object* response = NULL; + struct json_object* id = NULL; + struct pakfire_digests digests; + const char* __id = NULL; + char* hexdigest = NULL; + char* buffer = NULL; + size_t length = 0; + struct stat stat; + int r; + + const int fd = fileno(f); + + // Stat the file + r = fstat(fd, &stat); + if (r) { + CTX_ERROR(service->ctx, "Could not stat %s: %s\n", path, strerror(errno)); + goto ERROR; + } + + // Compute the digest + r = pakfire_digests_compute_from_file(service->ctx, &digests, PAKFIRE_DIGEST_BLAKE2B512, f); + if (r) { + CTX_ERROR(service->ctx, "Could not compute the digest of %s: %s\n", + path, strerror(-r)); + goto ERROR; + } + + // Convert the digest into hex format + hexdigest = pakfire_digest_get_hex(&digests, PAKFIRE_DIGEST_BLAKE2B512); + if (!hexdigest) + goto ERROR; + + // Create a new transfer + r = pakfire_buildservice_create_transfer(&transfer, service, "/api/v1/uploads"); + if (r) + goto ERROR; + + // Enable authentication + r = pakfire_downloader_transfer_auth(transfer); + if (r) + goto ERROR; + + // Add the filename parameter + r = pakfire_downloader_transfer_add_param(transfer, "filename", "%s", filename); + if (r) + goto ERROR; + + // Add the size parameter + r = pakfire_downloader_transfer_add_param(transfer, "size", "%jd", stat.st_size); + if (r) + goto ERROR; + + // Add the hexdigest algo parameter + r = pakfire_downloader_transfer_add_param(transfer, "hexdigest_algo", "%s", "blake2b512"); + if (r) + goto ERROR; + + // Add the hexdigest parameter + r = pakfire_downloader_transfer_add_param(transfer, "hexdigest", "%s", hexdigest); + if (r) + goto ERROR; + + // Write the response to the buffer + r = pakfire_downloader_transfer_set_output_buffer(transfer, &buffer, &length); + if (r) + goto ERROR; + + // Run the transfer + r = pakfire_downloader_transfer_run(transfer, PAKFIRE_TRANSFER_NO_PROGRESS); + if (r) + goto ERROR; + + // Parse the JSON response + response = pakfire_json_parse(service->ctx, buffer, length); + if (!response) { + CTX_ERROR(service->ctx, "Could not parse response\n"); + r = -EBADMSG; + goto ERROR; + } + + // Fetch the ID + r = json_object_object_get_ex(response, "id", &id); + if (r == 0) { + CTX_ERROR(service->ctx, "Could not fetch ID from response\n"); + r = -EBADMSG; + goto ERROR; + } + + // Extract the UUID + __id = json_object_get_string(id); + if (!__id) { + CTX_ERROR(service->ctx, "Could not fetch ID from response\n"); + r = -EBADMSG; + goto ERROR; + } + + // Return the UUID + *uuid = strdup(__id); + if (!*uuid) { + r = -errno; + goto ERROR; + } + + // Success + r = 0; + +ERROR: + if (transfer) + pakfire_downloader_transfer_unref(transfer); + if (response) + json_object_put(response); + if (hexdigest) + free(hexdigest); + if (buffer) + free(buffer); + + return r; +} + +static int pakfire_buildservice_upload_payload(struct pakfire_buildservice* service, + const char* filename, const char* uuid, FILE* f) { + struct pakfire_transfer* transfer = NULL; + char url[PATH_MAX]; + int r; + + // Make the URL + r = pakfire_string_format(url, "/api/v1/uploads/%s", uuid); + if (r) + goto ERROR; + + // Create a new transfer + r = pakfire_buildservice_create_transfer(&transfer, service, url); + if (r) + goto ERROR; + + // Set the title + r = pakfire_downloader_transfer_set_title(transfer, filename); + if (r) + goto ERROR; + + // Set source file + r = pakfire_downloader_transfer_set_input(transfer, f); + if (r) + goto ERROR; + + // Run the transfer + r = pakfire_downloader_transfer_run(transfer, 0); + if (r) + goto ERROR; + +ERROR: + if (transfer) + pakfire_downloader_transfer_unref(transfer); + + return r; +} + +PAKFIRE_EXPORT int pakfire_buildservice_upload(struct pakfire_buildservice* service, + const char* path, const char* filename) { + char basename[NAME_MAX]; + char* uuid = NULL; + FILE* f = NULL; + int r; + + // Compute the basename + r = pakfire_path_basename(basename, path); + if (r) + goto ERROR; + + // Set the basename as default filename + if (!filename) + filename = basename; + + // Open the source file + f = fopen(path, "r"); + if (!f) { + CTX_ERROR(service->ctx, "Could not open file for upload %s: %m\n", path); + return -errno; + } + + // Create a new upload + r = pakfire_buildservice_create_upload(service, path, filename, f, &uuid); + if (r) + goto ERROR; + + CTX_DEBUG(service->ctx, "Created a new download (%s)\n", uuid); + + // Send the payload + r = pakfire_buildservice_upload_payload(service, filename, uuid, f); + if (r) + goto ERROR; + +ERROR: + if (uuid) + free(uuid); + if (f) + fclose(f); + + return r; +} + PAKFIRE_EXPORT int pakfire_buildservice_list_uploads( struct pakfire_buildservice* service, struct json_object** p) { struct pakfire_transfer* transfer = NULL; diff --git a/src/libpakfire/include/pakfire/buildservice.h b/src/libpakfire/include/pakfire/buildservice.h index b5b7fe578..80576e623 100644 --- a/src/libpakfire/include/pakfire/buildservice.h +++ b/src/libpakfire/include/pakfire/buildservice.h @@ -34,6 +34,8 @@ struct pakfire_buildservice* pakfire_buildservice_unref(struct pakfire_buildserv // Uploads +int pakfire_buildservice_upload(struct pakfire_buildservice* service, + const char* path, const char* filename); int pakfire_buildservice_list_uploads( struct pakfire_buildservice* service, struct json_object** uploads); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 4e0dbbc9f..6121cc9b9 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -87,6 +87,7 @@ global: pakfire_buildservice_ref; pakfire_buildservice_unref; pakfire_buildservice_list_uploads; + pakfire_buildservice_upload; # dependencies pakfire_static_version_compare;