]> git.ipfire.org Git - pakfire.git/commitdiff
build: Add CLI switch to write the build log to file
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 14 Feb 2025 15:12:16 +0000 (15:12 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 14 Feb 2025 17:07:05 +0000 (17:07 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/cli/lib/build.c
src/pakfire/job.c
src/pakfire/log_file.c
src/pakfire/log_file.h
tests/libpakfire/log_file.c

index 405cd1efa22db0735706af35c333fc3b3d88f93a..75b0febc1d3f08cf04858fced29473c036fc33ba 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <pakfire/archive.h>
 #include <pakfire/build.h>
+#include <pakfire/log_file.h>
 #include <pakfire/package.h>
 #include <pakfire/pakfire.h>
 #include <pakfire/path.h>
@@ -47,6 +48,10 @@ struct cli_local_args {
                BUILD_ENABLE_TESTS    = (1 << 3),
        } flags;
 
+       // Log file
+       struct pakfire_log_file* log_file;
+       const char* log_path;
+
        // Makefiles
        char* makefiles[MAX_MAKEFILES];
        unsigned int num_makefiles;
@@ -56,14 +61,16 @@ enum {
        OPT_DISABLE_CCACHE   = 1,
        OPT_DISABLE_SNAPSHOT = 2,
        OPT_DISABLE_TESTS    = 3,
-       OPT_NON_INTERACTIVE  = 4,
-       OPT_TARGET           = 5,
+       OPT_LOG_FILE         = 4,
+       OPT_NON_INTERACTIVE  = 5,
+       OPT_TARGET           = 6,
 };
 
 static struct argp_option options[] = {
        { "disable-ccache",   OPT_DISABLE_CCACHE,      NULL, 0, "Disable the ccache",     0 },
        { "disable-snapshot", OPT_DISABLE_SNAPSHOT,    NULL, 0, "Do not use the snapshot", 0 },
        { "disable-tests",    OPT_DISABLE_TESTS,       NULL, 0, "Do not run tests",        0 },
+       { "log-file",         OPT_LOG_FILE,          "PATH", 0, "Writes the log to a file", 0 },
        { "non-interactive",  OPT_NON_INTERACTIVE,     NULL, 0, "Run the build non-interactively", 0 },
        { "target",           OPT_TARGET,          "TARGET", 0, "Output all packages into this directory", 0 },
        { NULL },
@@ -85,6 +92,10 @@ static error_t parse(int key, char* arg, struct argp_state* state, void* data) {
                        args->flags &= ~BUILD_ENABLE_TESTS;
                        break;
 
+               case OPT_LOG_FILE:
+                       args->log_path = arg;
+                       break;
+
                case OPT_NON_INTERACTIVE:
                        args->flags &= ~BUILD_INTERACTIVE;
                        break;
@@ -113,34 +124,43 @@ static void log_callback(void* data, int priority, const char* file, int line,
 
 static void log_callback(void* data, int priority, const char* file, int line,
                const char* function, const char* format, va_list args) {
-       va_list args_copy;
+       const struct cli_local_args* local_args = data;
+       char* buffer = NULL;
+       ssize_t length;
+       int r;
+
+       // Format the line
+       length = vasprintf(&buffer, format, args);
+       if (length < 0)
+               return;
 
-       // Make a copy of args because we can only use them once...
-       va_copy(args_copy, args);
        switch (priority) {
                // Print messages to standard output
                case LOG_INFO:
-                       vfprintf(stdout, format, args_copy);
+                       fprintf(stdout, "%s", buffer);
                        break;
 
                // Highlight any warnings
                case LOG_WARNING:
                        fputs(color_yellow(), stderr);
-                       vfprintf(stderr, format, args_copy);
+                       fprintf(stderr, "%s", buffer);
                        fputs(color_reset(), stderr);
                        break;
 
                // Highlight any error messages
                case LOG_ERR:
                        fputs(color_highlight(), stderr);
-                       vfprintf(stderr, format, args_copy);
+                       fprintf(stderr, "%s", buffer);
                        fputs(color_reset(), stderr);
                        break;
        }
-       va_end(args_copy);
 
-       // Send everything to the default logger, too
-       pakfire_log_syslog(NULL, priority, file, line, function, format, args);
+       // Write to the log file
+       if (local_args->log_file)
+               pakfire_log_file_write(local_args->log_file, buffer, length);
+
+       if (buffer)
+               free(buffer);
 }
 
 static int result_callback(struct pakfire_ctx* ctx, struct pakfire* pakfire,
@@ -217,7 +237,7 @@ int cli_build(void* data, int argc, char* argv[]) {
                goto ERROR;
 
        // Replace the logger
-       pakfire_ctx_set_log_callback(global_args->ctx, log_callback, NULL);
+       pakfire_ctx_set_log_callback(global_args->ctx, log_callback, &local_args);
 
        // Use the snapshot?
        if (local_args.flags & BUILD_ENABLE_SNAPSHOT)
@@ -235,6 +255,14 @@ int cli_build(void* data, int argc, char* argv[]) {
        if (!(local_args.flags & BUILD_ENABLE_TESTS))
                flags |= PAKFIRE_BUILD_DISABLE_TESTS;
 
+       // Create the log file
+       if (local_args.log_path) {
+               r = pakfire_log_file_create(&local_args.log_file,
+                               global_args->ctx, local_args.log_path, NULL, 0);
+               if (r < 0)
+                       goto ERROR;
+       }
+
        // Setup the build environment
        r = cli_setup_build(&build, global_args, flags);
        if (r < 0)
@@ -251,6 +279,8 @@ int cli_build(void* data, int argc, char* argv[]) {
        }
 
 ERROR:
+       if (local_args.log_file)
+               pakfire_log_file_unref(local_args.log_file);
        if (build)
                pakfire_build_unref(build);
 
index 8468c55db7e15fcdb1fa908c1f58df8906e40717..a6374ae5c29699750f5d80cd23d73ea9ffb690f0 100644 (file)
@@ -659,7 +659,7 @@ static int pakfire_job_child(struct pakfire_job* job) {
        pakfire_ctx_set_log_callback(ctx, pakfire_job_log, job);
 
        // Open a new log file
-       r = pakfire_log_file_create(&job->log.file, ctx, job->id, PAKFIRE_LOG_FILE_COMPRESS);
+       r = pakfire_log_file_create(&job->log.file, ctx, NULL, job->id, PAKFIRE_LOG_FILE_COMPRESS);
        if (r < 0) {
                ERROR(ctx, "Could not open log file: %s\n", strerror(-r));
                goto ERROR;
index 7b54c4356137fe65d7201849d175a844bc5a16da..dab4a03eee92277500becca5a4ddbb2532f7c4ac 100644 (file)
@@ -37,6 +37,11 @@ struct pakfire_log_file {
        // Flags
        int flags;
 
+       // Internal Flags
+       enum pakfire_log_file_internal_flags {
+               PAKFIRE_LOG_FILE_UNLINK = (1 << 0),
+       } internal_flags;
+
        // Path
        char path[PATH_MAX];
 
@@ -48,16 +53,19 @@ static void pakfire_log_file_free(struct pakfire_log_file* self) {
        // Close the log file
        pakfire_log_file_close(self);
 
-       // Free all held resources
-       if (*self->path)
-               unlink(self->path);
+       // Unlink the file
+       if (self->internal_flags & PAKFIRE_LOG_FILE_UNLINK) {
+               if (*self->path)
+                       unlink(self->path);
+       }
+
        if (self->ctx)
                pakfire_ctx_unref(self->ctx);
        free(self);
 }
 
 int pakfire_log_file_create(struct pakfire_log_file** file, struct pakfire_ctx* ctx,
-               const char* filename, int flags) {
+               const char* path, const char* filename, int flags) {
        struct pakfire_log_file* self = NULL;
        int r;
 
@@ -80,16 +88,35 @@ int pakfire_log_file_create(struct pakfire_log_file** file, struct pakfire_ctx*
        if (r < 0)
                goto ERROR;
 
-       // Make some path
-       r = pakfire_string_set(self->path, PAKFIRE_TMP_DIR "/pakfire-log.XXXXXX");
-       if (r < 0)
-               goto ERROR;
+       // Store the path
+       if (path) {
+               r = pakfire_string_set(self->path, path);
+               if (r < 0)
+                       goto ERROR;
 
-       // Create a new temporary file
-       self->f = pakfire_mktemp(self->path, 0600);
-       if (!self->f) {
-               r = -errno;
-               goto ERROR;
+               // Open the file
+               self->f = fopen(self->path, "w");
+               if (!self->f) {
+                       ERROR(self->ctx, "Failed to open %s for writing: %m\n", self->path);
+                       goto ERROR;
+               }
+
+       // If no path has been given, we create a new temporary file
+       } else {
+               // Make some path
+               r = pakfire_string_set(self->path, PAKFIRE_TMP_DIR "/pakfire-log.XXXXXX");
+               if (r < 0)
+                       goto ERROR;
+
+               // Create a new temporary file
+               self->f = pakfire_mktemp(self->path, 0600);
+               if (!self->f) {
+                       r = -errno;
+                       goto ERROR;
+               }
+
+               // Remove the temporary file afterwards
+               self->internal_flags |= PAKFIRE_LOG_FILE_UNLINK;
        }
 
        // If we want to write the log file compressed, we replace the file handle
index 2f60aa343c830d7313c8ca3b983f39534512ea94..584cfcd3613bb535889fa186e97ca2afc21e9d53 100644 (file)
@@ -34,7 +34,7 @@ enum pakfire_log_file_flags {
 };
 
 int pakfire_log_file_create(struct pakfire_log_file** file,
-       struct pakfire_ctx* ctx, const char* filename, int flags);
+       struct pakfire_ctx* ctx, const char* path, const char* filename, int flags);
 struct pakfire_log_file* pakfire_log_file_ref(struct pakfire_log_file* self);
 struct pakfire_log_file* pakfire_log_file_unref(struct pakfire_log_file* self);
 
index aeb37a5c3f080f15b177d8befb9b6a2586554115..845effed8bfe0f2f231ba470287902f921db3f4d 100644 (file)
@@ -31,7 +31,7 @@ static int __test_simple(const struct test* t, int flags) {
        int r = EXIT_FAILURE;
 
        // Create a new log file
-       ASSERT_SUCCESS(pakfire_log_file_create(&file, t->ctx, "test.log", flags));
+       ASSERT_SUCCESS(pakfire_log_file_create(&file, t->ctx, NULL, "test.log", flags));
 
        // Store a copy of the path
        ASSERT_SUCCESS(pakfire_string_set(path, pakfire_log_file_path(file)));