diff options
Diffstat (limited to 'src/cli')
-rw-r--r-- | src/cli/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/cli/commands.c | 242 | ||||
-rw-r--r-- | src/cli/commands.h | 15 | ||||
-rw-r--r-- | src/cli/main.c | 50 | ||||
-rw-r--r-- | src/cli/updater.c | 143 | ||||
-rw-r--r-- | src/cli/updater.h | 6 |
6 files changed, 468 insertions, 0 deletions
diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt new file mode 100644 index 0000000..fc46a42 --- /dev/null +++ b/src/cli/CMakeLists.txt @@ -0,0 +1,12 @@ +SET(FRONTEND_NAME "OFCL") + +SET(CLI_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/commands.c + ${CMAKE_CURRENT_SOURCE_DIR}/commands.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/updater.c + ${CMAKE_CURRENT_SOURCE_DIR}/updater.h +) + +add_executable(${FRONTEND_NAME} ${CLI_SOURCES}) +target_link_libraries(${FRONTEND_NAME} PRIVATE libofqt) diff --git a/src/cli/commands.c b/src/cli/commands.c new file mode 100644 index 0000000..4bac2f7 --- /dev/null +++ b/src/cli/commands.c @@ -0,0 +1,242 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "steam.h" +#include "toast.h" + +#include "commands.h" +#include "updater.h" + +#define ARRAY_LEN(arr) sizeof(arr) / sizeof(arr[0]) + +static int install(int, char**); +static int update(int, char**); +static int run(int, char**); +static int info(int, char**); + +const struct Command commands[] = { + { .name = "install", .func = install, .description = "Install OpenFortress"}, + { .name = "update", .func = update, .description = "Update an existing install"}, + { .name = "run", .func = run, .description = "Run OpenFortress"}, + { .name = "info", .func = info, .description = "Show info about the current setup"}, +}; +const size_t commands_size = ARRAY_LEN(commands); + +static int install(int c, char** v) +{ + int exit_val = EXIT_SUCCESS; + char* of_dir = NULL; + char* remote = NULL; + for (int i = 1; i < c; ++i) + { + if (!strcmp(v[i], "--dir")) + { + if (!v[++i]) + { + puts("No Directory specified"); + return EXIT_FAILURE; + } + of_dir = strdup(v[i]); + printf("Using %s as the directory\n", of_dir); + } + else if (!strcmp(v[i], "--remote")) + { + if (!v[++i]) + { + puts("No URL specified"); + return EXIT_FAILURE; + } + remote = strdup(v[i]); + printf("Using %s as the server\n", remote); + } + else + { + if (strcmp(v[i], "--help")) + printf("%s is not a valid flag\n\n", v[i]); + + puts( + "OFCL install\n" + "\t--dir\t\tspecify where to download OpenFortress to\n" + "\t--remote\tspecify the server to use\n" + "\t--help\t\tshows this text" + ); + return EXIT_FAILURE; + } + } + if (!of_dir) + of_dir = getOpenFortressDir(); + + if (getLocalRevision(of_dir) >= 0) + { + puts("OpenFortress is already installed"); + exit_val = EXIT_FAILURE; + goto install_cleanup; + } + + if (!remote) + remote = getLocalRemote(of_dir); + + int remote_rev = getLatestRemoteRevision(remote); + + if (remote_rev != -1) + { + update_setup(of_dir, remote, 0, remote_rev); + } + else + { + puts("Failed to get the latest revision"); + exit_val = EXIT_FAILURE; + } + + install_cleanup: + if (remote) + free(remote); + free(of_dir); + + return exit_val; +} + +static int update(int c, char** v) +{ + int exit_val = EXIT_SUCCESS; + int force = 0; + char* of_dir = NULL; + char* remote = NULL; + for (int i = 1; i < c; ++i) + { + if (!strcmp(v[i], "--force")) + force = 1; + else if (!strcmp(v[i], "--dir")) + { + if (!v[++i]) + { + puts("No Directory specified"); + return EXIT_FAILURE; + } + of_dir = strdup(v[i]); + printf("Using %s as the directory\n", of_dir); + } + else if (!strcmp(v[i], "--remote")) + { + if (!v[++i]) + { + puts("No URL specified"); + return EXIT_FAILURE; + } + remote = strdup(v[i]); + printf("Using %s as the server\n", remote); + } + else + { + if (strcmp(v[i], "--help")) + printf("%s is not a valid flag\n\n", v[i]); + + puts( + "OFCL update\n" + "\t--force\t\tforce update\n" + "\t--dir\t\tspecify where to download OpenFortress to\n" + "\t--remote\tspecify the server to use\n" + "\t--help\t\tshows this text" + ); + return EXIT_FAILURE; + } + } + + if (!of_dir) + of_dir = getOpenFortressDir(); + + int local_rev = getLocalRevision(of_dir); + if (force) + { + local_rev = 0; + } + else if (0 > local_rev) + { + puts("OpenFortress is not installed"); + exit_val = EXIT_FAILURE; + goto update_cleanup; + } + + if (!remote) + remote = getLocalRemote(of_dir); + + if (!strlen(remote)) + { + puts("Remote is invalid"); + exit_val = EXIT_FAILURE; + goto update_cleanup; + } + + int remote_rev = getLatestRemoteRevision(remote); + + if (remote_rev == -1) + { + puts("Failed to get the latest revision"); + exit_val = EXIT_FAILURE; + goto update_cleanup; + } + else if (remote_rev <= local_rev) + { + puts("Already up to date"); + goto update_cleanup; + } + + update_setup(of_dir, remote, local_rev, remote_rev); + + update_cleanup: + if (remote) + free(remote); + free(of_dir); + return exit_val; +} + +static int run(int c, char** v) +{ + int exit_val = EXIT_SUCCESS; + char* of_dir = getOpenFortressDir(); + + int local_rev = getLocalRevision(of_dir); + if (0 > local_rev) + { + puts("OpenFortress is not installed"); + exit_val = EXIT_FAILURE; + goto run_cleanup; + } + + if (getSteamPID() == -1) + { + puts("Steam is not running"); + exit_val = EXIT_FAILURE; + goto run_cleanup; + } + + runOpenFortress(); + + run_cleanup: + free(of_dir); + return exit_val; +} + +static int info(int c, char** v) +{ + char* of_dir = getOpenFortressDir(); + if (!of_dir) + of_dir = strdup("Not Found"); + printf("Install Directory:\n\t%s\n", of_dir); + + char* remote = getLocalRemote(of_dir); + printf("Server:\n\t%s\n", remote); + free(remote); + + int local_rev = getLocalRevision(of_dir); + printf("Revision:\t\n"); + if (local_rev == -1) + puts("\tNot installed"); + else + printf("\t%i\n", local_rev); + + free(of_dir); + + return EXIT_SUCCESS; +} diff --git a/src/cli/commands.h b/src/cli/commands.h new file mode 100644 index 0000000..d55edb9 --- /dev/null +++ b/src/cli/commands.h @@ -0,0 +1,15 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include <stddef.h> + +struct Command { + char* name; + int (*func)(int, char**); + char* description; +}; + +extern const struct Command commands[]; +extern const size_t commands_size; + +#endif
\ No newline at end of file diff --git a/src/cli/main.c b/src/cli/main.c new file mode 100644 index 0000000..7971c7d --- /dev/null +++ b/src/cli/main.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "net.h" +#include "commands.h" + +static void help() +{ + fprintf(stderr, "OFCL <command>\n"); \ + + size_t longestStr; + size_t length; + + if (commands_size) + { + longestStr = 0; + + for (size_t i = 0; i < commands_size; ++i) + { + length = strlen(commands[i].name); + + if (length > longestStr) longestStr = length; + } + + fprintf(stderr, "\nList of commands:\n"); + for (size_t i = 0; i < commands_size; ++i) + { + fprintf(stderr, "\t%-*s\t %s\n", (int)longestStr, commands[i].name, commands[i].description); + } + } +} + +int main(int argc, char** argv) +{ + net_init(); + atexit(net_deinit); + + for (int i = 1; i < argc; ++i) + { + for (size_t j = 0; j < commands_size; ++j) + { + if (!strcmp(commands[j].name, argv[i])) + return commands[j].func(argc-i, argv+i); + } + } + + help(); + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/src/cli/updater.c b/src/cli/updater.c new file mode 100644 index 0000000..8b0cc03 --- /dev/null +++ b/src/cli/updater.c @@ -0,0 +1,143 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +#include "fs.h" +#include "toast.h" + +#include "updater.h" + +#include <assert.h> + +#define THREAD_COUNT 8 + +struct thread_object_info { + int working; + + char* of_dir; + char* remote; + struct revision_t* rev; + size_t index; +}; + +static void* thread_download(void* pinfo) +{ + struct thread_object_info* info = pinfo; + if (info) + { + char* of_dir = info->of_dir; + char* remote = info->remote; + struct revision_t* rev = info->rev; + size_t i = info->index; + + struct file_info* file = &rev->files[i]; + if (file->type == TYPE_WRITE) + { + fprintf(stderr, "\rChecking %lu/%lu (%s)", i+1, rev->file_count, file->object); + + if (verifyFileHash(of_dir, file)) + { + fprintf(stderr, "\rDownloading %lu/%lu (%s)", i+1, rev->file_count, file->object); + downloadObject(of_dir, remote, file); + } + } + } + + info->working = 0; + pthread_exit(0); + + return NULL; +} + + +void update_setup(char* of_dir, char* remote, int local_rev, int remote_rev) +{ + struct revision_t* rev = fastFowardRevisions(remote, local_rev, remote_rev); + + if (rev) + { + pthread_t download_threads[THREAD_COUNT] = {0}; + struct thread_object_info thread_info[THREAD_COUNT] = {0}; + size_t tindex = 0; + + for (size_t i = 0; i < rev->file_count; ++i) + { + while (thread_info[tindex].working) + { + tindex = (tindex+1) % THREAD_COUNT; + } + + pthread_t* thread = &download_threads[tindex]; + struct thread_object_info* info = &thread_info[tindex]; + + info->working = 1; + info->of_dir = of_dir; + info->remote = remote; + info->rev = rev; + info->index = i; + + pthread_create(thread, NULL, thread_download, info); + } + + for (size_t i = 0; i < THREAD_COUNT; ++i) + { + pthread_t* thread = &download_threads[i]; + if (*thread) + pthread_join(*thread, NULL); + } + + for (size_t i = 0; i < rev->file_count; ++i) + { + struct file_info* file = &rev->files[i]; + if (file->type != TYPE_MKDIR) + continue; + + size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1; + char* buf = malloc(len); + snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path); + makeDir(buf); + free(buf); + } + + fprintf(stderr, "\rInstalling..."); + for (size_t i = 0; i < rev->file_count; ++i) + { + struct file_info* file = &rev->files[i]; + + switch (file->type) + { + case TYPE_WRITE: + case TYPE_MKDIR: + { + int k = applyObject(of_dir, file); + if (k) + { + printf("Failed to write %s\n", file->path); + } + } + break; + + case TYPE_DELETE: + { + size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1; + char* buf = malloc(len); + snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path); + if (isFile(buf) && remove(buf)) + { + printf("Failed to delete %s\n", file->path); + } + free(buf); + } + break; + } + } + + removeObjects(of_dir); + setLocalRemote(of_dir, remote); + setLocalRevision(of_dir, remote_rev); + + fprintf(stderr, "\rUpdated OpenFortress\n"); + freeRevision(rev); + } +} diff --git a/src/cli/updater.h b/src/cli/updater.h new file mode 100644 index 0000000..71fc751 --- /dev/null +++ b/src/cli/updater.h @@ -0,0 +1,6 @@ +#ifndef UPDATER_H +#define UPDATER_H + +void update_setup(char*, char*, int, int); + +#endif
\ No newline at end of file |