mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Add self-contained release packaging for Linux, macOS, and Windows.
Resolve asset/progress paths for AppImage and .app bundles, and ship GitHub Actions builds on version tags. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f55216b764
commit
f8e27e8b53
10 changed files with 711 additions and 18 deletions
201
util.c
201
util.c
|
|
@ -1,9 +1,208 @@
|
|||
#include "maturita.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Utilities */
|
||||
/* Portable data / progress paths */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
char *app_progress_dir;
|
||||
char *app_progress_u1;
|
||||
char *app_progress_u2;
|
||||
char *app_progress_u3;
|
||||
char *app_settings_file;
|
||||
char *app_progress_net;
|
||||
char *app_progress_hw;
|
||||
char *app_progress_mluvnice;
|
||||
char *app_progress_cetba;
|
||||
|
||||
static char *dup_dirname(const char *path) {
|
||||
char *tmp = g_strdup(path);
|
||||
char *dir;
|
||||
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
dir = g_path_get_dirname(tmp);
|
||||
g_free(tmp);
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Absolute path of this process's executable, or NULL. */
|
||||
static char *executable_path(void) {
|
||||
#ifdef _WIN32
|
||||
wchar_t wbuf[MAX_PATH];
|
||||
DWORD n = GetModuleFileNameW(NULL, wbuf, MAX_PATH);
|
||||
char *out;
|
||||
|
||||
if (n == 0 || n >= MAX_PATH)
|
||||
return NULL;
|
||||
out = g_utf16_to_utf8((const gunichar2 *)wbuf, -1, NULL, NULL, NULL);
|
||||
return out;
|
||||
#elif defined(__APPLE__)
|
||||
char *buf;
|
||||
uint32_t size = 0;
|
||||
|
||||
_NSGetExecutablePath(NULL, &size);
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
buf = g_malloc(size);
|
||||
if (_NSGetExecutablePath(buf, &size) != 0) {
|
||||
g_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
{
|
||||
char *real = g_canonicalize_filename(buf, NULL);
|
||||
|
||||
g_free(buf);
|
||||
return real ? real : NULL;
|
||||
}
|
||||
#else
|
||||
return g_file_read_link("/proc/self/exe", NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean dir_has_stylesheet(const char *dir) {
|
||||
char *css;
|
||||
gboolean ok;
|
||||
|
||||
if (!dir || !dir[0])
|
||||
return FALSE;
|
||||
css = g_build_filename(dir, CSS_FILE, NULL);
|
||||
ok = g_file_test(css, G_FILE_TEST_IS_REGULAR);
|
||||
g_free(css);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static char *macos_resources_dir(const char *exe) {
|
||||
char *macos_dir;
|
||||
char *contents;
|
||||
char *resources;
|
||||
|
||||
if (!exe)
|
||||
return NULL;
|
||||
macos_dir = dup_dirname(exe);
|
||||
if (!macos_dir)
|
||||
return NULL;
|
||||
if (!g_str_has_suffix(macos_dir, "MacOS")) {
|
||||
g_free(macos_dir);
|
||||
return NULL;
|
||||
}
|
||||
contents = dup_dirname(macos_dir);
|
||||
g_free(macos_dir);
|
||||
if (!contents)
|
||||
return NULL;
|
||||
resources = g_build_filename(contents, "Resources", NULL);
|
||||
g_free(contents);
|
||||
if (!dir_has_stylesheet(resources)) {
|
||||
g_free(resources);
|
||||
return NULL;
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
/* Directory next to Foo.app when exe is .../Foo.app/Contents/MacOS/maturita. */
|
||||
static char *macos_app_parent_dir(const char *exe) {
|
||||
char *macos_dir;
|
||||
char *contents;
|
||||
char *app_bundle;
|
||||
char *parent;
|
||||
|
||||
if (!exe)
|
||||
return NULL;
|
||||
macos_dir = dup_dirname(exe);
|
||||
if (!macos_dir || !g_str_has_suffix(macos_dir, "MacOS")) {
|
||||
g_free(macos_dir);
|
||||
return NULL;
|
||||
}
|
||||
contents = dup_dirname(macos_dir);
|
||||
g_free(macos_dir);
|
||||
if (!contents)
|
||||
return NULL;
|
||||
app_bundle = dup_dirname(contents);
|
||||
g_free(contents);
|
||||
if (!app_bundle)
|
||||
return NULL;
|
||||
parent = dup_dirname(app_bundle);
|
||||
g_free(app_bundle);
|
||||
return parent;
|
||||
}
|
||||
|
||||
static void set_progress_paths(const char *write_root) {
|
||||
g_free(app_progress_dir);
|
||||
g_free(app_progress_u1);
|
||||
g_free(app_progress_u2);
|
||||
g_free(app_progress_u3);
|
||||
g_free(app_settings_file);
|
||||
g_free(app_progress_net);
|
||||
g_free(app_progress_hw);
|
||||
g_free(app_progress_mluvnice);
|
||||
g_free(app_progress_cetba);
|
||||
|
||||
app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL);
|
||||
app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL);
|
||||
app_progress_u2 = g_build_filename(app_progress_dir, "unit2.conf", NULL);
|
||||
app_progress_u3 = g_build_filename(app_progress_dir, "unit3.conf", NULL);
|
||||
app_settings_file = g_build_filename(app_progress_dir, "settings.conf", NULL);
|
||||
app_progress_net = g_build_filename(app_progress_dir, "net.conf", NULL);
|
||||
app_progress_hw = g_build_filename(app_progress_dir, "hw.conf", NULL);
|
||||
app_progress_mluvnice = g_build_filename(app_progress_dir, "mluvnice.conf", NULL);
|
||||
app_progress_cetba = g_build_filename(app_progress_dir, "cetba.conf", NULL);
|
||||
}
|
||||
|
||||
/* Resolve read-only asset root, chdir there, and point progress at a writable
|
||||
* location (next to the AppImage / .app, or beside the binary / source tree). */
|
||||
void setup_portable_paths(void) {
|
||||
const char *appdir = g_getenv("APPDIR");
|
||||
const char *appimage = g_getenv("APPIMAGE");
|
||||
char *exe = executable_path();
|
||||
char *exe_dir = exe ? dup_dirname(exe) : NULL;
|
||||
char *data_dir = NULL;
|
||||
char *write_root = NULL;
|
||||
char *cwd;
|
||||
|
||||
if (appdir && dir_has_stylesheet(appdir))
|
||||
data_dir = g_strdup(appdir);
|
||||
if (!data_dir)
|
||||
data_dir = macos_resources_dir(exe);
|
||||
if (!data_dir && exe_dir && dir_has_stylesheet(exe_dir))
|
||||
data_dir = g_strdup(exe_dir);
|
||||
|
||||
cwd = g_get_current_dir();
|
||||
if (!data_dir && dir_has_stylesheet(cwd))
|
||||
data_dir = g_strdup(cwd);
|
||||
if (!data_dir && cwd)
|
||||
data_dir = g_strdup(cwd);
|
||||
|
||||
if (appimage && appimage[0])
|
||||
write_root = dup_dirname(appimage);
|
||||
if (!write_root)
|
||||
write_root = macos_app_parent_dir(exe);
|
||||
if (!write_root && exe_dir)
|
||||
write_root = g_strdup(exe_dir);
|
||||
if (!write_root && data_dir)
|
||||
write_root = g_strdup(data_dir);
|
||||
if (!write_root)
|
||||
write_root = g_strdup(".");
|
||||
|
||||
set_progress_paths(write_root);
|
||||
|
||||
if (data_dir && g_chdir(data_dir) != 0)
|
||||
g_warning("Could not chdir to data directory '%s'", data_dir);
|
||||
|
||||
g_free(cwd);
|
||||
g_free(write_root);
|
||||
g_free(data_dir);
|
||||
g_free(exe_dir);
|
||||
g_free(exe);
|
||||
}
|
||||
|
||||
char *normalize_answer(const char *input) {
|
||||
GString *pre = g_string_new(NULL);
|
||||
GString *out = g_string_new(NULL);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue