/tests/libpakfire/makefile
/tests/libpakfire/packager
/tests/libpakfire/parser
+/tests/libpakfire/progressbar
/tests/libpakfire/repo
/tests/libpakfire/util
/tmp
src/libpakfire/pakfire.c \
src/libpakfire/parser.c \
src/libpakfire/problem.c \
+ src/libpakfire/progressbar.c \
src/libpakfire/pwd.c \
src/libpakfire/relation.c \
src/libpakfire/relationlist.c \
src/libpakfire/include/pakfire/parser.h \
src/libpakfire/include/pakfire/private.h \
src/libpakfire/include/pakfire/problem.h \
+ src/libpakfire/include/pakfire/progressbar.h \
src/libpakfire/include/pakfire/pwd.h \
src/libpakfire/include/pakfire/relation.h \
src/libpakfire/include/pakfire/relationlist.h \
tests/libpakfire/makefile \
tests/libpakfire/packager \
tests/libpakfire/parser \
+ tests/libpakfire/progressbar \
tests/libpakfire/repo \
tests/libpakfire/util
$(TESTSUITE_LDADD) \
$(PAKFIRE_LIBS)
+dist_tests_libpakfire_progressbar_SOURCES = \
+ tests/libpakfire/progressbar.c \
+ src/libpakfire/progressbar.c \
+ src/libpakfire/util.c
+
+tests_libpakfire_progressbar_CPPFLAGS = \
+ $(TESTSUITE_CPPFLAGS) \
+ $(JSON_C_CFLAGS) \
+ -DPAKFIRE_PRIVATE
+
+tests_libpakfire_progressbar_LDADD = \
+ $(TESTSUITE_LDADD) \
+ $(PAKFIRE_LIBS) \
+ $(ARCHIVE_LIBS) \
+ $(JSON_C_LIBS) \
+ $(UUID_LIBS)
+
dist_tests_libpakfire_repo_SOURCES = \
tests/libpakfire/repo.c
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifndef PAKFIRE_PROGRESSBAR_H
+#define PAKFIRE_PROGRESSBAR_H
+
+#ifdef PAKFIRE_PRIVATE
+
+#include <stdio.h>
+
+#include <pakfire/types.h>
+
+struct pakfire_progressbar;
+
+int pakfire_progressbar_create(
+ struct pakfire_progressbar** progressbar, Pakfire pakfire, FILE* f);
+
+struct pakfire_progressbar* pakfire_progressbar_ref(struct pakfire_progressbar* p);
+struct pakfire_progressbar* pakfire_progressbar_unref(struct pakfire_progressbar* p);
+
+int pakfire_progressbar_start(struct pakfire_progressbar* p, unsigned long value);
+int pakfire_progressbar_update(struct pakfire_progressbar* p, unsigned long value);
+int pakfire_progressbar_increment(struct pakfire_progressbar* p);
+int pakfire_progressbar_finish(struct pakfire_progressbar* p);
+
+#endif
+
+#endif /* PAKFIRE_PROGRESSBAR_H */
struct json_object* pakfire_json_parse_from_file(Pakfire pakfire, const char* path);
+// Time Stuff
+
+struct timespec timespec_add(const struct timespec* t1, const struct timespec* t2);
+
+struct timespec timespec_from_ms(int milliseconds);
+
+int timespec_lt(struct timespec* t1, struct timespec* t2);
+
#endif
#endif /* PAKFIRE_UTIL_H */
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <time.h>
+
+#include <pakfire/logging.h>
+#include <pakfire/pakfire.h>
+#include <pakfire/progressbar.h>
+#include <pakfire/types.h>
+#include <pakfire/util.h>
+
+#define REDRAW_TIMEOUT 100
+
+struct pakfire_progressbar {
+ Pakfire pakfire;
+ int nrefs;
+
+ enum pakfire_progressbar_status {
+ PAKFIRE_PROGRESSBAR_INIT = 0,
+ PAKFIRE_PROGRESSBAR_RUNNING,
+ PAKFIRE_PROGRESSBAR_FINISHED,
+ } status;
+
+ // The progress
+ unsigned long value;
+ unsigned long value_max;
+ unsigned long value_redraw;
+ unsigned long update_interval;
+
+ // Store terminal settings globally
+ struct pakfire_terminal {
+ FILE* f;
+ int rows;
+ int cols;
+ } terminal;
+
+ struct timespec time_start;
+ struct timespec time_redraw;
+};
+
+static int pakfire_progressbar_update_terminal_size(struct pakfire_progressbar* p) {
+ struct winsize w;
+
+ int r = ioctl(fileno(p->terminal.f), TIOCGWINSZ, &w);
+ if (r) {
+ ERROR(p->pakfire, "Could not determine terminal size: %s\n", strerror(errno));
+ }
+
+ // Save result
+ p->terminal.rows = w.ws_row;
+ p->terminal.cols = w.ws_col;
+
+ return 0;
+}
+
+static void pakfire_progressbar_free(struct pakfire_progressbar* p) {
+ pakfire_unref(p->pakfire);
+ free(p);
+}
+
+int pakfire_progressbar_create(struct pakfire_progressbar** progressbar,
+ Pakfire pakfire, FILE* f) {
+ struct pakfire_progressbar* p = calloc(1, sizeof(*p));
+ if (!p)
+ return ENOMEM;
+
+ p->pakfire = pakfire_ref(pakfire);
+ p->nrefs = 1;
+
+ // Save output file
+ if (f)
+ p->terminal.f = f;
+ else
+ p->terminal.f = stderr;
+
+ // Determine terminal size
+ int r = pakfire_progressbar_update_terminal_size(p);
+ if (r)
+ goto ERROR;
+
+ // Done
+ *progressbar = p;
+ return 0;
+
+ERROR:
+ pakfire_progressbar_free(p);
+
+ return r;
+}
+
+struct pakfire_progressbar* pakfire_progressbar_ref(struct pakfire_progressbar* p) {
+ ++p->nrefs;
+
+ return p;
+}
+
+struct pakfire_progressbar* pakfire_progressbar_unref(struct pakfire_progressbar* p) {
+ if (--p->nrefs > 0)
+ return p;
+
+ pakfire_progressbar_free(p);
+ return NULL;
+}
+
+int pakfire_progressbar_start(struct pakfire_progressbar* p, unsigned long value) {
+ if (p->status != PAKFIRE_PROGRESSBAR_INIT)
+ return EINVAL;
+
+ // Set status
+ p->status = PAKFIRE_PROGRESSBAR_RUNNING;
+
+ // Store maximum value
+ p->value_max = value;
+
+ // Redraw immediately
+ p->value_redraw = 0;
+
+ // Set start time
+ int r = clock_gettime(CLOCK_MONOTONIC, &p->time_start);
+ if (r) {
+ ERROR(p->pakfire, "Could not set start time: %s\n", strerror(errno));
+ return r;
+ }
+
+ // Calculate update interval
+ p->update_interval = p->value_max / p->terminal.cols;
+
+ return pakfire_progressbar_update(p, 0);
+}
+
+static int pakfire_progressbar_redraw(struct pakfire_progressbar* p);
+
+int pakfire_progressbar_update(struct pakfire_progressbar* p, unsigned long value) {
+ if (p->status == PAKFIRE_PROGRESSBAR_INIT)
+ return EINVAL;
+
+ p->value = value;
+
+ return pakfire_progressbar_redraw(p);
+}
+
+int pakfire_progressbar_increment(struct pakfire_progressbar* p) {
+ return pakfire_progressbar_update(p, p->value + 1);
+}
+
+int pakfire_progressbar_finish(struct pakfire_progressbar* p) {
+ if (p->status != PAKFIRE_PROGRESSBAR_RUNNING)
+ return EINVAL;
+
+ // Set status
+ p->status = PAKFIRE_PROGRESSBAR_FINISHED;
+
+ // Set to maximum value
+ int r = pakfire_progressbar_update(p, p->value_max);
+ if (r)
+ return r;
+
+ // Finish line
+ r = fputs("\n", p->terminal.f);
+ if (r <= 0 || r == EOF)
+ return 1;
+
+ return 0;
+}
+
+/*
+ This functions determines whether this progressbar needs to be redrawn
+ and sets any markers to determine the next redraw.
+*/
+static int pakfire_progressbar_needs_redraw(struct pakfire_progressbar* p) {
+ struct timespec now;
+
+ // Fetch the current time
+ int r = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (r)
+ return r;
+
+ // Redraw when we surpassed the next redraw value
+ if (p->value >= p->value_redraw)
+ goto REDRAW;
+
+ // Redraw when we hit the timeout
+ if (timespec_lt(&now, &p->time_redraw))
+ goto REDRAW;
+
+ // Redraw when we are finished
+ if (p->status == PAKFIRE_PROGRESSBAR_FINISHED)
+ goto REDRAW;
+
+ // No need to redraw
+ return 0;
+
+REDRAW:
+ // Compute next redraw steps
+ p->value_redraw = p->value + p->update_interval;
+
+ struct timespec timeout = timespec_from_ms(REDRAW_TIMEOUT);
+ p->time_redraw = timespec_add(&now, &timeout);
+
+ return 1;
+}
+
+static int pakfire_progressbar_redraw(struct pakfire_progressbar* p) {
+ // Return when we should not be redrawing
+ if (!pakfire_progressbar_needs_redraw(p))
+ return 0;
+
+ fprintf(p->terminal.f, "\r%lu/%lu", p->value, p->value_max);
+
+ return 0;
+}
#include <pakfire/private.h>
#include <pakfire/types.h>
+#define NSEC_PER_SEC 1000000000
+
PAKFIRE_EXPORT int pakfire_string_startswith(const char* s, const char* prefix) {
return !strncmp(s, prefix, strlen(prefix));
}
return json;
}
+
+// Time Stuff
+
+static void timespec_normalize(struct timespec* t) {
+ while (t->tv_nsec >= NSEC_PER_SEC) {
+ t->tv_sec++;
+ t->tv_nsec -= NSEC_PER_SEC;
+ }
+
+ while (t->tv_nsec <= -NSEC_PER_SEC) {
+ t->tv_sec--;
+ t->tv_nsec += NSEC_PER_SEC;
+ }
+}
+
+struct timespec timespec_add(const struct timespec* t1, const struct timespec* t2) {
+ struct timespec r = {
+ .tv_sec = t1->tv_sec + t2->tv_sec,
+ .tv_nsec = t2->tv_nsec + t2->tv_nsec,
+ };
+
+ // Correct any negative values
+ timespec_normalize(&r);
+
+ return r;
+}
+
+struct timespec timespec_from_ms(int milliseconds) {
+ struct timespec t = {
+ .tv_sec = (milliseconds / 1000),
+ .tv_nsec = (milliseconds % 1000) * 1000000,
+ };
+
+ return t;
+}
+
+int timespec_lt(struct timespec* t1, struct timespec* t2) {
+ return (
+ t1->tv_sec < t2->tv_sec ||
+ (t1->tv_sec == t2->tv_sec && t1->tv_nsec < t2->tv_nsec)
+ );
+}
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <pakfire/progressbar.h>
+
+#include "../testsuite.h"
+
+static int test_run(const struct test* t) {
+ struct pakfire_progressbar* p;
+
+ ASSERT_SUCCESS(pakfire_progressbar_create(&p, t->pakfire, NULL));
+
+ ASSERT(pakfire_progressbar_finish(p) == EINVAL);
+
+ ASSERT_SUCCESS(pakfire_progressbar_start(p, 1000));
+
+ for (unsigned int i = 0; i < 1000; i++) {
+ ASSERT_SUCCESS(pakfire_progressbar_increment(p));
+ usleep(2500);
+ }
+
+ ASSERT_SUCCESS(pakfire_progressbar_finish(p));
+
+ ASSERT_NULL(pakfire_progressbar_unref(p));
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char** argv) {
+ testsuite_add_test(test_run);
+
+ return testsuite_run();
+}
} \
} while (0)
+#define ASSERT_NULL(expr) \
+ do { \
+ if (!((expr) == NULL)) { \
+ LOG_ERROR("Failed assertion: " #expr " == NULL %s:%d %s\n", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
#define ASSERT_SUCCESS(expr) \
do { \
if ((expr)) { \
} \
} while (0)
+#define ASSERT_ERRNO(expr, e) \
+ do { \
+ if (!(expr)) { \
+ LOG_ERROR("Failed assertion: " #expr " unexpectedly didn't fail in %s:%d %s\n", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ return EXIT_FAILURE; \
+ } \
+ if (errno != e) { \
+ LOG_ERROR("Failed assertion: " #expr " failed with (%d - %s) " \
+ "but was expected to fail with (%d - %s) in %s:%d\n", \
+ errno, strerror(errno), e, strerror(e), __FILE__, __LINE__); \
+ return EXIT_FAILURE; \
+ } \
+ } while (0)
+
#define ASSERT_STRING_EQUALS(value, string) \
do { \
if (!value) { \