diff --git a/Common/Cpp/Filesystem/Filesystem_Linux.h b/Common/Cpp/Filesystem/Filesystem_Linux.h index 54d8a8ed84..7c58d37cce 100644 --- a/Common/Cpp/Filesystem/Filesystem_Linux.h +++ b/Common/Cpp/Filesystem/Filesystem_Linux.h @@ -6,6 +6,10 @@ #include #include +#include +#include +#include +#include "Common/Cpp/Strings/StringTools.h" #include "FilePath.h" #include "Filesystem.h" @@ -22,7 +26,74 @@ Path application_binary_path(){ return Path(); } Path application_install_path(){ - // TODO: This is just a placeholder. + // Check for AppImage environment variables to find the root directory, if running as an AppImage. + // PA_APPIMAGE_DIR is set by Azure via a patched AppRun script. + { + char* dir = std::getenv("PA_APPIMAGE_DIR"); + if (dir != nullptr){ + return dir; + } + } + { + char* path = std::getenv("APPIMAGE"); + if (path != nullptr){ + return std::filesystem::absolute(path).parent_path().lexically_normal(); + } + } + { + char* app_dir = std::getenv("APPDIR"); + if (app_dir != nullptr){ + std::ifstream mount_info(Filesystem::Path("/proc/self/mountinfo").stdpath()); + if (mount_info.is_open()){ + std::string line; + while (std::getline(mount_info, line)){ + size_t dash_sep = line.find(" - "); + if (dash_sep == std::string::npos) { + continue; + } + + // 1. Extract and tokenize the "pre" segment (before " - ") + std::vector pre; + { + std::string pre_str = line.substr(0, dash_sep); + std::stringstream ss(pre_str); + std::string token; + while (ss >> token) { + pre.push_back(token); + } + } + + // 2. Extract and tokenize the "post" segment (after " - ") + std::vector post; + { + std::string post_str = line.substr(dash_sep + 3); + std::stringstream ss(post_str); + std::string token; + while (ss >> token) { + post.push_back(token); + } + } + + // 3. Validation bounds check + if (pre.size() < 5 || post.size() < 2){ + continue; + } + + // 4. Clean out octal space encodings using standard string operations + std::string mount_point = StringTools::replace(pre[4], "\\040", " "); + std::string source = StringTools::replace(post[1], "\\040", " "); + + if (mount_point == app_dir && source.ends_with(".AppImage")){ + Filesystem::Path dir_path = Filesystem::Path(source).parent_path(); + Filesystem::Path abs_path = Filesystem::absolute(dir_path); + return abs_path.lexically_normal(); + } + } + } + } + } + + // Fallback return application_binary_path(); } Path application_scratch_path(){ diff --git a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp index 10dfb029fc..3ee92f2ec0 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp @@ -62,80 +62,9 @@ namespace{ -Filesystem::Path get_application_base_dir_path(){ -#if defined(__linux__) - // Check for AppImage environment variables to find the root directory, if running as an AppImage. - // PA_APPIMAGE_DIR is set by Azure via a patched AppRun script. - { - char* dir = std::getenv("PA_APPIMAGE_DIR"); - if (dir != nullptr){ - return dir; - } - } - { - char* path = std::getenv("APPIMAGE"); - if (path != nullptr){ - return std::filesystem::absolute(path).parent_path().lexically_normal(); - } - } - { - char* app_dir = std::getenv("APPDIR"); - if (app_dir != nullptr){ - std::ifstream mount_info(Filesystem::Path("/proc/self/mountinfo").stdpath()); - if (mount_info.is_open()){ - std::string line; - while (std::getline(mount_info, line)){ - size_t dash_sep = line.find(" - "); - if (dash_sep == std::string::npos) { - continue; - } - - // 1. Extract and tokenize the "pre" segment (before " - ") - std::vector pre; - { - std::string pre_str = line.substr(0, dash_sep); - std::stringstream ss(pre_str); - std::string token; - while (ss >> token) { - pre.push_back(token); - } - } - - // 2. Extract and tokenize the "post" segment (after " - ") - std::vector post; - { - std::string post_str = line.substr(dash_sep + 3); - std::stringstream ss(post_str); - std::string token; - while (ss >> token) { - post.push_back(token); - } - } - - // 3. Validation bounds check - if (pre.size() < 5 || post.size() < 2){ - continue; - } - - // 4. Clean out octal space encodings using standard string operations - std::string mount_point = StringTools::replace(pre[4], "\\040", " "); - std::string source = StringTools::replace(post[1], "\\040", " "); - - if (mount_point == app_dir && source.ends_with(".AppImage")){ - Filesystem::Path dir_path = Filesystem::Path(source).parent_path(); - Filesystem::Path abs_path = Filesystem::absolute(dir_path); - return abs_path.lexically_normal(); - } - } - } - } - } -#endif - return Filesystem::application_install_path(); -} std::string get_resource_path(){ // Find the resource directory. - Filesystem::Path base = get_application_base_dir_path(); + Filesystem::Path base = Filesystem::application_install_path(); Filesystem::Path path = base; for (size_t c = 0; c < 5; c++){ Filesystem::Path try_path = path / "Resources/"; @@ -150,7 +79,7 @@ std::string get_unittest_resource_path(){ // Find the unit test resource directory. // Try the intended folder name first. - Filesystem::Path base = get_application_base_dir_path(); + Filesystem::Path base = Filesystem::application_install_path(); Filesystem::Path path = base; for (size_t c = 0; c < 5; c++){ Filesystem::Path try_path = path / "UnitTestResources/"; @@ -175,7 +104,7 @@ std::string get_unittest_resource_path(){ std::string get_training_path(){ // Find the training data directory. - Filesystem::Path base = get_application_base_dir_path(); + Filesystem::Path base = Filesystem::application_install_path(); Filesystem::Path path = base; for (size_t c = 0; c < 5; c++){ Filesystem::Path try_path = path / "TrainingData/";