diff options
author | Alex Zolotarev <deathbaba@gmail.com> | 2011-10-31 00:14:52 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 01:27:10 +0300 |
commit | eea66458919753af7edc32b9210adfa1a1f36751 (patch) | |
tree | 4545e07fbda279938b77b45069c7973c2437a857 | |
parent | 29f6e38b349ca9620ed36a637c692fbccb12eb32 (diff) |
Completed platform refactoring and fixed paths for resources/writable dirs
-rw-r--r-- | generator/generator_tests/generator_tests.pro | 1 | ||||
-rw-r--r-- | generator/generator_tool/generator_tool.pro | 3 | ||||
-rw-r--r-- | indexer/indexer_tests/indexer_tests.pro | 1 | ||||
-rw-r--r-- | map/benchmark_tool/benchmark_tool.pro | 1 | ||||
-rw-r--r-- | map/map_tests/map_tests.pro | 3 | ||||
-rw-r--r-- | platform/platform.hpp | 20 | ||||
-rw-r--r-- | platform/platform_android.cpp | 21 | ||||
-rw-r--r-- | platform/platform_ios.mm | 21 | ||||
-rw-r--r-- | platform/platform_linux.cpp | 55 | ||||
-rw-r--r-- | platform/platform_mac.mm | 85 | ||||
-rw-r--r-- | platform/platform_qt.cpp | 111 | ||||
-rw-r--r-- | platform/platform_tests/platform_test.cpp | 23 | ||||
-rw-r--r-- | platform/platform_win.cpp | 65 | ||||
-rw-r--r-- | search/search_tests/search_tests.pro | 1 | ||||
-rw-r--r-- | words/words_tests/words_tests.pro | 1 | ||||
-rw-r--r-- | yg/yg_tests/yg_tests.pro | 1 |
16 files changed, 193 insertions, 220 deletions
diff --git a/generator/generator_tests/generator_tests.pro b/generator/generator_tests/generator_tests.pro index 36b00958dc..97c259edcd 100644 --- a/generator/generator_tests/generator_tests.pro +++ b/generator/generator_tests/generator_tests.pro @@ -14,6 +14,7 @@ win32 { LIBS *= -lShell32 win32-g++: LIBS *= -lpthread } +macx*: LIBS *= "-framework Foundation" HEADERS += \ diff --git a/generator/generator_tool/generator_tool.pro b/generator/generator_tool/generator_tool.pro index 26865caeb9..80ffe26c08 100644 --- a/generator/generator_tool/generator_tool.pro +++ b/generator/generator_tool/generator_tool.pro @@ -12,7 +12,8 @@ TEMPLATE = app # needed for Platform::WorkingDir() and unicode combining QT *= core -win32:LIBS += -lShell32 +win32: LIBS *= -lShell32 +macx*: LIBS *= "-framework Foundation" SOURCES += \ generator_tool.cpp \ diff --git a/indexer/indexer_tests/indexer_tests.pro b/indexer/indexer_tests/indexer_tests.pro index 818a99c9da..ae389e57ef 100644 --- a/indexer/indexer_tests/indexer_tests.pro +++ b/indexer/indexer_tests/indexer_tests.pro @@ -13,6 +13,7 @@ win32 { LIBS *= -lShell32 win32-g++: LIBS *= -lpthread } +macx*: LIBS *= "-framework Foundation" HEADERS += \ test_polylines.hpp \ diff --git a/map/benchmark_tool/benchmark_tool.pro b/map/benchmark_tool/benchmark_tool.pro index ebf46deca2..03ed3d426f 100644 --- a/map/benchmark_tool/benchmark_tool.pro +++ b/map/benchmark_tool/benchmark_tool.pro @@ -16,6 +16,7 @@ win32 { LIBS *= -lShell32 win32-g++: LIBS *= -lpthread } +macx*: LIBS *= "-framework Foundation" SOURCES += \ features_loading.cpp \ diff --git a/map/map_tests/map_tests.pro b/map/map_tests/map_tests.pro index 37fdecf9a7..16fd5ea02e 100644 --- a/map/map_tests/map_tests.pro +++ b/map/map_tests/map_tests.pro @@ -12,10 +12,11 @@ include($$ROOT_DIR/common.pri) QT *= core opengl -win32 { +win32* { LIBS *= -lShell32 -lOpengl32 win32-g++: LIBS *= -lpthread } +macx*: LIBS *= "-framework Foundation" SOURCES += \ ../../testing/testingmain.cpp \ diff --git a/platform/platform.hpp b/platform/platform.hpp index 793f8bacb1..ad745ae478 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -16,8 +16,22 @@ class Platform protected: string m_writableDir, m_resourcesDir; class PlatformImpl; + /// Used only on those platforms where needed PlatformImpl * m_impl; + /// Internal function to use files from writable dir if they override the same in the resources + string ReadPathForFile(string const & file) const + { + string fullPath = m_writableDir + file; + if (!IsFileExists(fullPath)) + { + fullPath = m_resourcesDir + file; + if (!IsFileExists(fullPath)) + MYTHROW(FileAbsentException, ("File doesn't exist", fullPath)); + } + return fullPath; + } + public: Platform(); ~Platform(); @@ -46,11 +60,7 @@ public: /// @return false if file is not exist bool GetFileSize(string const & file, uint64_t & size) const; /// Simple file existing check - bool IsFileExists(string const & file) const - { - uint64_t dummy; - return GetFileSize(file, dummy); - } + bool IsFileExists(string const & file) const; //@} int CpuCores() const; diff --git a/platform/platform_android.cpp b/platform/platform_android.cpp index f85780d697..adbbb5c12e 100644 --- a/platform/platform_android.cpp +++ b/platform/platform_android.cpp @@ -7,26 +7,14 @@ #include <unistd.h> #include <sys/stat.h> -static string ReadPathForFile(string const & writableDir, - string const & resourcesDir, string const & file) -{ - string fullPath = writableDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - { - fullPath = resourcesDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - MYTHROW(FileAbsentException, ("File doesn't exist", fullPath)); - } - return fullPath; -} - Platform::Platform() {} Platform::~Platform() {} -static bool IsFilePresent(string const & file) +/// @warning doesn't work for files inside .apk (zip)!!! +bool Platform::IsFileExists(string const & file) const { struct stat s; return stat(file.c_str(), &s) == 0; @@ -34,9 +22,8 @@ static bool IsFilePresent(string const & file) ModelReader * Platform::GetReader(string const & file) const { - // can't use Platform::IsFileExists here to avoid recursion - if (IsFilePresent(m_writableDir + file)) - return new FileReader(ReadPathForFile(m_writableDir, m_resourcesDir, file), 10, 12); + if (IsFileExists(m_writableDir + file)) + return new FileReader(ReadPathForFile(file), 10, 12); else { // paths from GetFilesInDir will already contain "assets/" if (file.find("assets/") != string::npos) diff --git a/platform/platform_ios.mm b/platform/platform_ios.mm index c951332022..21e5714762 100644 --- a/platform/platform_ios.mm +++ b/platform/platform_ios.mm @@ -91,6 +91,12 @@ Platform::~Platform() delete m_impl; } +bool Platform::IsFileExists(string const & file) const +{ + struct stat s; + return stat(file.c_str(), &s) == 0; +} + void Platform::GetFilesInDir(string const & directory, string const & mask, FilesList & res) const { DIR * dir; @@ -144,22 +150,9 @@ void Platform::GetFontNames(FilesList & res) const sort(res.begin(), res.end()); } -static string ReadPathForFile(string const & writableDir, - string const & resourcesDir, string const & file) -{ - string fullPath = writableDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - { - fullPath = resourcesDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - MYTHROW(FileAbsentException, ("File doesn't exist", fullPath)); - } - return fullPath; -} - ModelReader * Platform::GetReader(string const & file) const { - return new FileReader(ReadPathForFile(m_writableDir, m_resourcesDir, file), 10, 12); + return new FileReader(ReadPathForFile(file), 10, 12); } int Platform::CpuCores() const diff --git a/platform/platform_linux.cpp b/platform/platform_linux.cpp index 748fd50dcd..be9b580cf4 100644 --- a/platform/platform_linux.cpp +++ b/platform/platform_linux.cpp @@ -4,33 +4,56 @@ #include <unistd.h> #include <sys/stat.h> -#define LOCALAPPDATA_DIR "MapsWithMe" +//static bool GetUserWritableDir(string & outDir) +//{ +// char * path = ::getenv("HOME"); +// if (path) +// { +// outDir = path; +// outDir += "/.MapsWithMe/"; +// ::mkdir(outDir.c_str(), 0755); +// return true; +// } +// return false; +//} -bool GetUserWritableDir(string & outDir) -{ - char * path = ::getenv("HOME"); - if (path) - { - outDir = path; - outDir += "." LOCALAPPDATA_DIR "/"; - ::mkdir(outDir.c_str(), 0755); - return true; - } - return false; -} - -/// @return full path including binary itself -bool GetPathToBinary(string & outPath) +/// @return directory where binary resides, including slash at the end +static bool GetBinaryFolder(string & outPath) { char path[4096] = {0}; if (0 < ::readlink("/proc/self/exe", path, ARRAY_SIZE(path))) { outPath = path; + outPath.erase(outPath.find_last_of('/') + 1); return true; } return false; } +Platform::Platform() +{ + // init directories + string path; + CHECK(GetBinaryFolder(path), ("Can't retrieve path to executable")); + + // @TODO implement correct resources and writable directories for public releases + m_resourcesDir = path + "../../../data"; + m_writableDir = m_resourcesDir; + + LOG(LDEBUG, ("Resources directory:", m_resourcesDir)); + LOG(LDEBUG, ("Writable directory:", m_writableDir)); +} + +Platform::~Platform() +{ +} + +bool Platform::IsFileExists(string const & file) const +{ + struct stat s; + return stat(file.c_str(), &s) == 0; +} + int Platform::CpuCores() const { long numCPU = sysconf(_SC_NPROCESSORS_ONLN); diff --git a/platform/platform_mac.mm b/platform/platform_mac.mm index 2eed808312..ae406f3caa 100644 --- a/platform/platform_mac.mm +++ b/platform/platform_mac.mm @@ -1,62 +1,65 @@ #include "platform.hpp" +#include "../base/logging.hpp" + #include "../std/target_os.hpp" -#include <glob.h> -#include <NSSystemDirectories.h> -#include <mach-o/dyld.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/sysctl.h> #include <IOKit/IOKitLib.h> +#include <Foundation/NSBundle.h> +#include <Foundation/NSPathUtilities.h> +#include <Foundation/NSAutoreleasePool.h> -#define LOCALAPPDATA_DIR "MapsWithMe" +#include <sys/stat.h> +#include <sys/sysctl.h> -static string ExpandTildePath(char const * path) +Platform::Platform() { - glob_t globbuf; - string result = path; + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success + // get resources directory path + string const resourcesPath = [[[NSBundle mainBundle] resourcePath] UTF8String]; + string const bundlePath = [[[NSBundle mainBundle] bundlePath] UTF8String]; + if (resourcesPath == bundlePath) { - if (globbuf.gl_pathc > 0) - result = globbuf.gl_pathv[0]; + // we're the console app, probably unit test, and path is our directory + m_resourcesDir = bundlePath + "/../../data/"; + m_writableDir = m_resourcesDir; + } + else + { + m_resourcesDir = resourcesPath + "/"; - globfree(&globbuf); + // get writable path +#ifndef OMIM_PRODUCTION + // developers can have symlink to data folder + char const * dataPath = "../../../../../data/"; + if (IsFileExists(m_resourcesDir + dataPath)) + m_writableDir = m_resourcesDir + dataPath; +#endif + + if (m_writableDir.empty()) + { + NSArray * dirPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString * supportDir = [dirPaths objectAtIndex:0]; + m_writableDir = [supportDir UTF8String]; + m_writableDir += "/MapsWithMe/"; + ::mkdir(m_writableDir.c_str(), 0755); + } } - return result; + [pool release]; + + LOG(LDEBUG, ("Resources Directory:", m_resourcesDir)); + LOG(LDEBUG, ("Writable Directory:", m_writableDir)); } -bool GetUserWritableDir(string & outDir) +Platform::~Platform() { - char pathBuf[PATH_MAX]; - NSSearchPathEnumerationState state = ::NSStartSearchPathEnumeration(NSApplicationSupportDirectory, NSUserDomainMask); - while ((state = NSGetNextSearchPathEnumeration(state, pathBuf))) - { - outDir = ExpandTildePath(pathBuf); - ::mkdir(outDir.c_str(), 0755); - outDir += "/" LOCALAPPDATA_DIR "/"; - ::mkdir(outDir.c_str(), 0755); - return true; - } - return false; } -/// @return full path including binary itself -bool GetPathToBinary(string & outPath) +bool Platform::IsFileExists(string const & file) const { - char path[MAXPATHLEN] = {0}; - uint32_t pathSize = ARRAY_SIZE(path); - if (0 == ::_NSGetExecutablePath(path, &pathSize)) - { - char fixedPath[MAXPATHLEN] = {0}; - if (::realpath(path, fixedPath)) - { - outPath = fixedPath; - return true; - } - } - return false; + struct stat s; + return stat(file.c_str(), &s) == 0; } int Platform::CpuCores() const diff --git a/platform/platform_qt.cpp b/platform/platform_qt.cpp index 10ab490789..17895bfe08 100644 --- a/platform/platform_qt.cpp +++ b/platform/platform_qt.cpp @@ -8,119 +8,10 @@ #include <QtCore/QFileInfo> #include <QtCore/QTemporaryFile> -// default writable directory name for dev/standalone installs -#define MAPDATA_DIR "data" -// default writable dir name in LocalAppData or ~/Library/AppData/ folders -#define LOCALAPPDATA_DIR "MapsWithMe" -// default Resources read-only dir -#define RESOURCES_DIR "Resources" - -/// @name Platform-dependent implementations in separate files -//@{ -bool GetUserWritableDir(string & outDir); -bool GetPathToBinary(string & outDir); -//@} - -static bool IsDirectoryWritable(string const & dir) -{ - if (!dir.empty()) - { - QString qDir = dir.c_str(); - if (dir[dir.size() - 1] != '/' && dir[dir.size() - 1] != '\\') - qDir.append('/'); - - QTemporaryFile file(qDir + "XXXXXX"); - if (file.open()) - return true; - } - return false; -} - -/// Scans all upper directories for the presence of given directory -/// @param[in] startPath full path to lowest file in hierarchy (usually binary) -/// @param[in] dirName directory name we want to be present -/// @return if not empty, contains full path to existing directory -static string DirFinder(string const & startPath, string dirName) -{ - char const SLASH = QDir::separator().toAscii(); - dirName = SLASH + dirName + SLASH; - - size_t slashPos = startPath.size(); - while (slashPos > 0 && (slashPos = startPath.rfind(SLASH, slashPos - 1)) != string::npos) - { - string const dir = startPath.substr(0, slashPos) + dirName; - if (QFileInfo(dir.c_str()).exists()) - return dir; - } - return string(); -} - -static bool GetOSSpecificResourcesDir(string const & exePath, string & dir) -{ - dir = DirFinder(exePath, RESOURCES_DIR); - return !dir.empty(); -} - -static void InitResourcesDir(string & dir) -{ - // Resources dir can be any "data" folder found in the nearest upper directory, - // where all necessary resources files are present and accessible - string exePath; - CHECK( GetPathToBinary(exePath), ("Can't get full path to executable") ); - dir = DirFinder(exePath, MAPDATA_DIR); - if (dir.empty()) - { - CHECK( GetOSSpecificResourcesDir(exePath, dir), ("Can't retrieve resources directory") ); - } - - /// @todo Check all necessary files -} - -static void InitWritableDir(string & dir) -{ - // Writable dir can be any "data" folder found in the nearest upper directory - // ./data - For Windows portable builds - // ../data - // ../../data - For developer builds - // etc. (for Mac in can be up to 6 levels above due to packages structure - // and if no _writable_ "data" folder was found, User/Application Data/MapsWithMe will be used - - string path; - CHECK( GetPathToBinary(path), ("Can't get full path to executable") ); - dir = DirFinder(path, MAPDATA_DIR); - if (dir.empty() || !IsDirectoryWritable(dir)) - { - CHECK( GetUserWritableDir(dir), ("Can't get User's Application Data writable directory") ); - } -} - -static string ReadPathForFile(string const & writableDir, - string const & resourcesDir, string const & file) -{ - string fullPath = writableDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - { - fullPath = resourcesDir + file; - if (!GetPlatform().IsFileExists(fullPath)) - MYTHROW(FileAbsentException, ("File doesn't exist", fullPath)); - } - return fullPath; -} - //////////////////////////////////////////////////////////////////////////////////////// -Platform::Platform() -{ - InitWritableDir(m_writableDir); - InitResourcesDir(m_resourcesDir); -} - -Platform::~Platform() -{ -} - ModelReader * Platform::GetReader(string const & file) const { - return new FileReader(ReadPathForFile(m_writableDir, m_resourcesDir, file), 10, 12); + return new FileReader(ReadPathForFile(file), 10, 12); } bool Platform::GetFileSize(string const & file, uint64_t & size) const diff --git a/platform/platform_tests/platform_test.cpp b/platform/platform_tests/platform_test.cpp index 5904700dee..c66cac2c3a 100644 --- a/platform/platform_tests/platform_test.cpp +++ b/platform/platform_tests/platform_test.cpp @@ -4,7 +4,7 @@ #include "../../defines.hpp" -#include "../../coding/writer.hpp" +#include "../../coding/file_writer.hpp" #include "../../coding/internal/file_data.hpp" #include "../../base/logging.hpp" @@ -72,13 +72,20 @@ UNIT_TEST(GetFilesInDir) TEST_EQUAL(files.size(), 0, ()); } -//UNIT_TEST(GetFileSize) -//{ -// Platform & pl = GetPlatform(); -// uint64_t size = 0; -// pl.GetFileSize(pl.ReadPathForFile("classificator.txt").c_str(), size); -// TEST_GREATER(size, 0, ("File classificator.txt should exist for test")); -//} +UNIT_TEST(GetFileSize) +{ + Platform & pl = GetPlatform(); + + { + FileWriter testFile(TEST_FILE_NAME); + testFile.Write("HOHOHO", 6); + } + uint64_t size = 0; + pl.GetFileSize(TEST_FILE_NAME, size); + TEST_EQUAL(size, 6, ()); + + FileWriter::DeleteFileX(TEST_FILE_NAME); +} UNIT_TEST(CpuCores) { diff --git a/platform/platform_win.cpp b/platform/platform_win.cpp index ff59584210..b0013e7c95 100644 --- a/platform/platform_win.cpp +++ b/platform/platform_win.cpp @@ -1,27 +1,28 @@ #include "platform.hpp" +#include "../coding/file_writer.hpp" + #include "../std/windows.hpp" #include <shlobj.h> +#include <sys/stat.h> -#define LOCALAPPDATA_DIR "MapsWithMe" - -bool GetUserWritableDir(string & outDir) +static bool GetUserWritableDir(string & outDir) { char pathBuf[MAX_PATH] = {0}; if (SUCCEEDED(::SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, pathBuf))) { outDir = pathBuf; ::CreateDirectoryA(outDir.c_str(), NULL); - outDir += "\\" LOCALAPPDATA_DIR "\\"; + outDir += "\\MapsWithMe\\"; ::CreateDirectoryA(outDir.c_str(), NULL); return true; } return false; } -/// @return full path including binary itself -bool GetPathToBinary(string & outPath) +/// @return Full path to the executable file +static bool GetPathToBinary(string & outPath) { // get path to executable char pathBuf[MAX_PATH] = {0}; @@ -33,6 +34,58 @@ bool GetPathToBinary(string & outPath) return false; } +Platform::Platform() +{ + string path; + CHECK(GetPathToBinary(path), ("Can't get path to binary")); + + // resources path: + // 1. try to use data folder in the same path as executable + // 2. if not found, try to use ..\..\..\data (for development only) + path.erase(path.find_last_of('\\')); + if (IsFileExists(path + "\\data\\")) + m_resourcesDir = path + "\\data\\"; + else + { +#ifndef OMIM_PRODUCTION + path.erase(path.find_last_of('\\')); + path.erase(path.find_last_of('\\')); + if (IsFileExists(path + "\\data\\")) + m_resourcesDir = path + "\\data\\"; +#else + CHECK(false, ("Can't find resources directory")); +#endif + } + + // writable path: + // 1. the same as resources if we have write access to this folder + // 2. otherwise, use system-specific folder + try + { + FileWriter tmpfile(m_resourcesDir + "mapswithmetmptestfile"); + tmpfile.Write("Hi from Alex!", 13); + FileWriter::DeleteFileX(m_resourcesDir + "mapswithmetmptestfile"); + m_writableDir = m_resourcesDir; + } + catch (FileWriter::RootException const &) + { + CHECK(GetUserWritableDir(m_writableDir), ("Can't get writable directory")); + } + + LOG(LDEBUG, ("Resources Directory:", m_resourcesDir)); + LOG(LDEBUG, ("Writable Directory:", m_writableDir)); +} + +Platform::~Platform() +{ +} + +bool Platform::IsFileExists(string const & file) const +{ + struct _stat s; + return _stat(file.c_str(), &s) == 0; +} + int Platform::CpuCores() const { SYSTEM_INFO sysinfo; diff --git a/search/search_tests/search_tests.pro b/search/search_tests/search_tests.pro index 5cc207fa37..5501deb87a 100644 --- a/search/search_tests/search_tests.pro +++ b/search/search_tests/search_tests.pro @@ -10,7 +10,6 @@ DEPENDENCIES = search platform indexer geometry coding base include($$ROOT_DIR/common.pri) -# needed for GetPlatform::ReadPathForFile() QT *= core win32 { diff --git a/words/words_tests/words_tests.pro b/words/words_tests/words_tests.pro index 161f38ed74..67443608eb 100644 --- a/words/words_tests/words_tests.pro +++ b/words/words_tests/words_tests.pro @@ -11,6 +11,7 @@ include($$ROOT_DIR/common.pri) QT *= core win32: LIBS *= -lshell32 +macx*: LIBS *= "-framework Foundation" SOURCES += $$ROOT_DIR/testing/testingmain.cpp \ sorted_index_test.cpp \ diff --git a/yg/yg_tests/yg_tests.pro b/yg/yg_tests/yg_tests.pro index 8ca0935ce2..d141f36380 100644 --- a/yg/yg_tests/yg_tests.pro +++ b/yg/yg_tests/yg_tests.pro @@ -14,6 +14,7 @@ win32 { LIBS *= -lopengl32 -lshell32 win32-g++: LIBS *= -lpthread } +macx*: LIBS *= "-framework Foundation" SOURCES += \ ../../testing/testingmain.cpp \ |