diff --git a/apps/projectGenerator b/apps/projectGenerator index 74afcd48555..bb6456ef735 160000 --- a/apps/projectGenerator +++ b/apps/projectGenerator @@ -1 +1 @@ -Subproject commit 74afcd48555ba9b3d0c430b2853ddad306a89b63 +Subproject commit bb6456ef735e16816e10ffea8fe44e70f0b7af0c diff --git a/libs/openFrameworks/utils/ofFileUtils.cpp b/libs/openFrameworks/utils/ofFileUtils.cpp index f699f783018..54ebea3e8b5 100644 --- a/libs/openFrameworks/utils/ofFileUtils.cpp +++ b/libs/openFrameworks/utils/ofFileUtils.cpp @@ -22,24 +22,31 @@ using std::istream; using std::ostream; using std::ios; -namespace{ +using std::cout; +using std::endl; + +namespace fs = of::filesystem; + +namespace { bool enableDataPath = true; //-------------------------------------------------- fs::path defaultDataPath(){ #if defined TARGET_OSX try { - return fs::canonical(ofFilePath::getCurrentExeDirFS() / "../../../data/"); - } catch(...) { - return ofFilePath::getCurrentExeDirFS() / "../../../data/"; + return fs::canonical(ofFilePath::getCurrentExeDir() / "../../../data/"); + } catch(fs::filesystem_error & e) { + ofLogWarning("ofFileUtils") << "defaultDataPath 1 " << e.what(); + return ofFilePath::getCurrentExeDir() / "../../../data/"; } #elif defined TARGET_ANDROID return string("sdcard/"); #else try { - return fs::canonical(ofFilePath::getCurrentExeDirFS() / "data/").make_preferred(); - } catch(...) { - return (ofFilePath::getCurrentExeDirFS() / "data/"); + return fs::canonical(ofFilePath::getCurrentExeDir() / "data").make_preferred(); + } catch(fs::filesystem_error & e) { + ofLogWarning("ofFileUtils") << "defaultDataPath 2 " << e.what(); + return (ofFilePath::getCurrentExeDir() / "data"); } #endif } @@ -53,15 +60,20 @@ namespace{ //-------------------------------------------------- fs::path & dataPathRoot() { static auto * dataPathRoot = new fs::path(defaultDataPath()); + // This is the most important change in the way OF handles paths. + try { + fs::current_path(*dataPathRoot); + } catch(fs::filesystem_error & e) { + ofLogError("ofFileUtils") << "dataPathRoot\n" << e.what(); + } return *dataPathRoot; } } namespace of{ namespace priv{ - void initfileutils() { - // FIXME: Why absolute? - defaultWorkingDirectory() = fs::absolute(fs::current_path()); + void initfileutils(){ + defaultWorkingDirectory() = dataPathRoot(); } } } @@ -693,7 +705,8 @@ std::string ofFile::getAbsolutePath() const { //------------------------------------------------------------------------------------------------------------ bool ofFile::canRead() const { - + auto perm = fs::status(myFile).permissions(); + #ifdef TARGET_WIN32 DWORD attr = GetFileAttributes(myFile.native().c_str()); if (attr == INVALID_FILE_ATTRIBUTES) @@ -704,7 +717,7 @@ bool ofFile::canRead() const { #else struct stat info; stat(path().c_str(), &info); // Error check omitted - auto perm = fs::status(myFile).permissions(); + #if defined(OF_USING_STD_FS) if(geteuid() == info.st_uid){ return (perm & fs::perms::owner_read) != fs::perms::none; @@ -727,6 +740,9 @@ bool ofFile::canRead() const { //------------------------------------------------------------------------------------------------------------ bool ofFile::canWrite() const { + + auto perm = fs::status(myFile).permissions(); + #ifdef TARGET_WIN32 DWORD attr = GetFileAttributes(myFile.native().c_str()); if (attr == INVALID_FILE_ATTRIBUTES){ @@ -737,8 +753,9 @@ bool ofFile::canWrite() const { #else struct stat info; stat(path().c_str(), &info); // Error check omitted - auto perm = fs::status(myFile).permissions(); + #if defined(OF_USING_STD_FS) + if(geteuid() == info.st_uid){ return (perm & fs::perms::owner_write) != fs::perms::none; }else if (getegid() == info.st_gid){ @@ -760,13 +777,16 @@ bool ofFile::canWrite() const { //------------------------------------------------------------------------------------------------------------ bool ofFile::canExecute() const { + + auto perm = fs::status(myFile).permissions(); #ifdef TARGET_WIN32 return getExtension() == "exe"; #else struct stat info; stat(path().c_str(), &info); // Error check omitted - auto perm = fs::status(myFile).permissions(); + #if defined(OF_USING_STD_FS) + if(geteuid() == info.st_uid){ return (perm & fs::perms::owner_exec) != fs::perms::none; }else if (getegid() == info.st_gid){ @@ -1216,7 +1236,8 @@ std::string ofDirectory::path() const { fs::path ofDirectory::getAbsolutePathFS() const { try { return fs::canonical(fs::absolute(myDir)); - } catch(...) { + } catch(fs::filesystem_error & e) { + ofLogWarning("ofFileUtils") << "ofDirectory::getAbsolutePath " << e.what(); return fs::absolute(myDir); } } @@ -1335,11 +1356,24 @@ bool ofDirectory::copyTo(const fs::path & _path, bool bRelativeToData, bool over //------------------------------------------------------------------------------------------------------------ bool ofDirectory::moveTo(const fs::path& path, bool bRelativeToData, bool overwrite){ - if(copyTo(path,bRelativeToData,overwrite)){ - return remove(true); + if (fs::exists(path)) { + if (overwrite) { + fs::remove_all(path); + } + else { + ofLogError("ofDirectory") << "moveTo(): destination folder exists, overwrite = false " << std::endl; + return false; + } } - - return false; + const fs::path & old = myDir; + try { + fs::rename(old, path); + } catch (fs::filesystem_error const& ex) { + ofLogError("ofDirectory") << "moveTo(): can't rename folder " << ex.code().message() << std::endl; + return false; + } + myDir = path; + return true; } //------------------------------------------------------------------------------------------------------------ @@ -1393,7 +1427,7 @@ std::size_t ofDirectory::listDir(){ return 0; } - if ( fs::exists(myDir) && fs::is_directory(myDir)){ + if (fs::exists(myDir) && fs::is_directory(myDir)){ for (const auto & f : fs::directory_iterator{ myDir }) { files.emplace_back(f.path(), ofFile::Reference); } @@ -1773,6 +1807,7 @@ fs::path ofFilePath::getPathForDirectoryFS(const fs::path & path){ return path / ""; #else auto sep = fs::path("/").make_preferred(); + // FIXME: ALERT funny path.back here() if(!path.empty() && ofToString(path.back()) != sep.string()){ return path / sep; }else{ @@ -1824,7 +1859,7 @@ std::string ofFilePath::getEnclosingDirectory(const fs::path & _filePath, bool b if(bRelativeToData){ fp = ofToDataPath(fp); } - return addTrailingSlash(fp.parent_path()); + return fp.parent_path().string(); } //------------------------------------------------------------------------------------------------------------ @@ -1840,7 +1875,8 @@ fs::path ofFilePath::getAbsolutePathFS(const fs::path & path, bool bRelativeToDa }else{ try{ return fs::canonical(fs::absolute(path)); - }catch(...){ + } catch(fs::filesystem_error & e) { + ofLogWarning("ofFileUtils") << "getAbsolutePath " << e.what(); return fs::absolute(path); } } @@ -1857,8 +1893,9 @@ bool ofFilePath::isAbsolute(const fs::path& path){ } //------------------------------------------------------------------------------------------------------------ -string ofFilePath::getCurrentWorkingDirectory(){ - return ofPathToString(fs::current_path()); +// FIXME: Deprecate +fs::path ofFilePath::getCurrentWorkingDirectory(){ + return fs::current_path(); } //------------------------------------------------------------------------------------------------------------ @@ -1888,20 +1925,28 @@ fs::path ofFilePath::getCurrentExePathFS(){ } return path; #elif defined(TARGET_WIN32) - vector executablePath(MAX_PATH); - DWORD result = ::GetModuleFileNameA(nullptr, &executablePath[0], static_cast(executablePath.size())); +// vector executablePath(MAX_PATH); + wchar_t executablePath[MAX_PATH]; + DWORD result = ::GetModuleFileNameW( + nullptr, + executablePath, + static_cast(MAX_PATH) + ); if (result == 0) { - ofLogError("ofFilePath") << "getCurrentExePath(): couldn't get path, GetModuleFileNameA failed"; + // Error + ofLogError("ofFilePath") << "getCurrentExePath(): couldn't get path, GetModuleFileNameW failed"; } else { - return string(executablePath.begin(), executablePath.begin() + result); +// return { executablePath.begin(), executablePath.begin() + result }; + return { executablePath }; } + #endif return ""; } //------------------------------------------------------------------------------------------------------------ -std::string ofFilePath::getCurrentExePath(){ - return ofPathToString(getCurrentExePathFS()); +fs::path ofFilePath::getCurrentExeDir(){ + return ofFilePath::getCurrentExePath().parent_path(); } //------------------------------------------------------------------------------------------------------------ @@ -1950,7 +1995,8 @@ bool ofRestoreWorkingDirectoryToDefault(){ try{ fs::current_path(defaultWorkingDirectory()); return true; - }catch(...){ + } catch(fs::filesystem_error & e) { + ofLogWarning("ofFileUtils") << "ofRestoreWorkingDirectoryToDefault " << e.what(); return false; } } @@ -1961,94 +2007,35 @@ void ofSetDataPathRoot(const fs::path& newRoot){ } //-------------------------------------------------- -fs::path ofToDataPathFS(const fs::path & path, bool makeAbsolute){ - if (makeAbsolute && path.is_absolute()) { - return path; - } - - if (!enableDataPath) { - return path; - } - - bool hasTrailingSlash = !path.empty() && path.generic_string().back()=='/'; - - // if our Current Working Directory has changed (e.g. file open dialog) -#ifdef TARGET_WIN32 - if (defaultWorkingDirectory() != fs::current_path()) { - // change our cwd back to where it was on app load - bool ret = ofRestoreWorkingDirectoryToDefault(); - if(!ret){ - ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory(); - } - } -#endif - - // this could be performed here, or wherever we might think we accidentally change the cwd, e.g. after file dialogs on windows - const auto & dataPath = dataPathRoot(); - fs::path inputPath(path); - fs::path outputPath; - - // if path is already absolute, just return it - if (inputPath.is_absolute()) { - try { - auto outpath = fs::canonical(inputPath).make_preferred(); - if(fs::is_directory(outpath) && hasTrailingSlash){ - return ofFilePath::addTrailingSlash(outpath); - }else{ - return outpath; - } - } - catch (...) { - return inputPath; - } - } - - // here we check whether path already refers to the data folder by looking for common elements - // if the path begins with the full contents of dataPathRoot then the data path has already been added - // we compare inputPath.toString() rather that the input var path to ensure common formatting against dataPath.toString() - auto dirDataPath = dataPath; - // also, we strip the trailing slash from dataPath since `path` may be input as a file formatted path even if it is a folder (i.e. missing trailing slash) - - // FIXME: unneeded after we remove string operations - dirDataPath = ofFilePath::addTrailingSlash(dataPath); - - auto relativeDirDataPath = ofFilePath::makeRelative(fs::current_path(), dataPath); - - // FIXME: unneeded after we remove string operations - relativeDirDataPath = ofFilePath::addTrailingSlash(relativeDirDataPath); - - // FIXME: this can be simplified without using string conversion - // if (inputPath.string().find(dirDataPath.string()) != 0 && inputPath.string().find(relativeDirDataPath.string())!=0) { - if (inputPath.string().find(dirDataPath.string()) != 0 && inputPath.string().find(relativeDirDataPath)!=0) { - // inputPath doesn't contain data path already, so we build the output path as the inputPath relative to the dataPath - if(makeAbsolute){ - outputPath = dirDataPath / inputPath; - }else{ - outputPath = relativeDirDataPath / inputPath; +fs::path ofToDataPath(const fs::path & path, bool makeAbsolute){ + fs::path outPath { path }; + if (path.is_absolute()) { + if (makeAbsolute) { + // nothing needed here. outPath is already path + } else { + auto current = fs::current_path(); + outPath = fs::relative(path, current); } } else { - // inputPath already contains data path, so no need to change - outputPath = inputPath; - } - - // finally, if we do want an absolute path and we don't already have one - if(makeAbsolute){ - // then we return the absolute form of the path - try { - auto outpath = fs::canonical(fs::absolute(outputPath)).make_preferred(); - if(fs::is_directory(outpath) && hasTrailingSlash){ - return ofFilePath::addTrailingSlash(outpath); - }else{ - return outpath; - } - } - catch (std::exception &) { - return fs::absolute(outputPath); + if (makeAbsolute) { + outPath = dataPathRoot() / path; + } else { + auto current = fs::current_path(); + outPath = fs::relative(dataPathRoot() / path, current); } - }else{ - // or output the relative path - return outputPath; } + + return outPath; +//// if our Current Working Directory has changed (e.g. file open dialog) +//#ifdef TARGET_WIN32 +// if (defaultWorkingDirectory() != fs::current_path()) { +// // change our cwd back to where it was on app load +// bool ret = ofRestoreWorkingDirectoryToDefault(); +// if(!ret){ +// ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory(); +// } +// } +//#endif } //-------------------------------------------------- diff --git a/libs/openFrameworks/utils/ofFileUtils.h b/libs/openFrameworks/utils/ofFileUtils.h index c2ed03af9f3..600b23a069e 100644 --- a/libs/openFrameworks/utils/ofFileUtils.h +++ b/libs/openFrameworks/utils/ofFileUtils.h @@ -417,7 +417,7 @@ class ofFilePath { /// \warning This location *may* change if you or a library calls the cd() /// std C function. /// \returns current working directory - static std::string getCurrentWorkingDirectory(); + static of::filesystem::path getCurrentWorkingDirectory(); /// Create a single path by joining path1 & path2 using a slash, /// ie. "/hello/world" + "foo/bar" -> "/hello/world/foo/bar". @@ -443,8 +443,7 @@ class ofFilePath { /// Mac: the Contents/MacOS folder within the application's .app bundle /// /// \returns current executable directory - static of::filesystem::path getCurrentExeDirFS(); - static std::string getCurrentExeDir(); + static of::filesystem::path getCurrentExeDir(); /// Get the absolute path to the user's home directory. /// diff --git a/tests/addons/ofxOsc/src/main.cpp b/tests/addons/ofxOsc/src/main.cpp index 2fd45934af5..d41451b1cad 100644 --- a/tests/addons/ofxOsc/src/main.cpp +++ b/tests/addons/ofxOsc/src/main.cpp @@ -15,7 +15,7 @@ class ofApp: public ofxUnitTestsApp { std::string str { "/string" }; ofxOscMessage m_str {str}; - ofxTest(m_str.getAddress() == "/string","ofxOscMessage{std::string"); + ofxTest(m_str.getAddress() == "/string","ofxOscMessage{std::string}"); std::string & strref = str; ofxOscMessage m_strref {strref}; diff --git a/tests/utils/fileUtils/bin/data/.gitkeep b/tests/utils/fileUtils/bin/data/.gitkeep new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/utils/fileUtils/bin/data/.gitkeep @@ -0,0 +1 @@ + diff --git a/tests/utils/fileUtils/src/main.cpp b/tests/utils/fileUtils/src/main.cpp index 59dbdb25a27..dcec1a054e7 100644 --- a/tests/utils/fileUtils/src/main.cpp +++ b/tests/utils/fileUtils/src/main.cpp @@ -2,21 +2,23 @@ #include "ofUtils.h" #include "ofxUnitTests.h" -of::filesystem::path initial_cwd; +namespace fs = of::filesystem; +fs::path initial_cwd; class ofApp: public ofxUnitTestsApp{ void run(){ ofDirectory dir("."); dir.create(true); dir.exists(); - for(auto f: dir){ - f.setWriteable(true); - if(f.isDirectory()){ - ofDirectory(f.path()).remove(true); - }else{ - f.remove(); - } - } + for(auto f: dir){ + f.setWriteable(true); + if(f.isDirectory()){ + std::cout << "will remove " << f.path() << std::endl; + ofDirectory(f.path()).remove(true); + }else{ + f.remove(); + } + } ofxTest(ofDirectory(".").getFiles().empty(),"removing old tests files","other tests will fail too"); @@ -202,13 +204,15 @@ class ofApp: public ofxUnitTestsApp{ //======================================================================== ofLogNotice() << ""; ofLogNotice() << "tests #4299"; - ofxTestEq(of::filesystem::path(ofFilePath::getCurrentWorkingDirectory()), initial_cwd, "ofFilePath::getCurrentWorkingDirectory()"); + ofxTestEq(fs::canonical(ofFilePath::getCurrentWorkingDirectory()), initial_cwd, "ofFilePath::getCurrentWorkingDirectory()"); + + if(ofGetTargetPlatform()==OF_TARGET_OSX){ - ofxTestEq(ofToDataPath("",false),"../../../data/","ofToDataPath relative"); + ofxTestEq(ofToDataPath("", false), ".", "ofToDataPath relative"); }else if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ - ofxTestEq(ofToDataPath("",false),"data\\","ofToDataPath relative"); + ofxTestEq(ofToDataPath("",false), ".", "ofToDataPath relative"); }else{ - ofxTestEq(ofToDataPath("",false),"data/","ofToDataPath relative"); + ofxTestEq(ofToDataPath("",false), ".", "ofToDataPath relative"); } @@ -230,22 +234,22 @@ class ofApp: public ofxUnitTestsApp{ } - //======================================================================== - ofLogNotice() << ""; - ofLogNotice() << "tests #4598"; - ofxTestEq(ofPathToString(ofToDataPath("")).back(), of::filesystem::path::preferred_separator, "ofToDataPath with empty string shouldn't crash"); + // //======================================================================== + // ofLogNotice() << ""; + // ofLogNotice() << "tests #4598"; + // ofxTestEq(ofPathToString(ofToDataPath("")).back(), of::filesystem::path::preferred_separator, "ofToDataPath with empty string shouldn't crash"); //======================================================================== ofLogNotice() << ""; ofLogNotice() << "tests #4563"; #ifdef TARGET_LINUX - ofxTestEq(ofToDataPath("a.txt"), "data/a.txt","#4563 test1"); - ofxTestEq(ofToDataPath("data.txt"), "data/data.txt", "#4563 test2"); - ofxTestEq(ofToDataPath(""), "data/", "#4563 test3"); + ofxTestEq(ofToDataPath("a.txt"), "a.txt","#4563 test1"); + ofxTestEq(ofToDataPath("data.txt"), "data.txt", "#4563 test2"); + ofxTestEq(ofToDataPath(""), "", "#4563 test3"); #elif defined(TARGET_OSX) - ofxTestEq(ofToDataPath("a.txt"), "../../../data/a.txt","#4563 test1"); - ofxTestEq(ofToDataPath("data.txt"), "../../../data/data.txt", "#4563 test2"); - ofxTestEq(ofToDataPath(""), "../../../data/", "#4563 test3"); + ofxTestEq(ofToDataPath("a.txt"), "a.txt","#4563 test1"); + ofxTestEq(ofToDataPath("data.txt"), "data.txt", "#4563 test2"); + ofxTestEq(ofToDataPath(""), ".", "#4563 test3"); #endif @@ -262,19 +266,29 @@ class ofApp: public ofxUnitTestsApp{ } //======================================================================== - ofLogNotice() << "#4564"; - dir.remove(true); - if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ - ofDirectory currentVideoDirectory(ofToDataPath("..\\..\\..\\video", true)); - auto path = currentVideoDirectory.path(); - std::string pathEnd("data\\..\\..\\..\\video\\"); - ofxTestEq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); - }else{ - ofDirectory currentVideoDirectory(ofToDataPath("../../../video", true)); - auto path = currentVideoDirectory.path(); - std::string pathEnd("data/../../../video/"); - ofxTestEq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); - } +// ofLogNotice() << "#4564"; + // no, this removes the data folder completely +//// dir.remove(true); +// if(ofGetTargetPlatform()==OF_TARGET_WINVS || ofGetTargetPlatform()==OF_TARGET_MINGW){ +// ofDirectory currentVideoDirectory(ofToDataPath("..\\..\\..\\video", true)); +// auto path = currentVideoDirectory.path(); +// std::string pathEnd("data\\..\\..\\..\\video\\"); +// ofxTestEq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); +// }else{ +// using std::cout; +// using std::endl; +// +// std::cout << 1 << std::endl; +// ofDirectory currentVideoDirectory(ofToDataPath("../../../video", true)); +// std::cout << 2 << std::endl; +// auto path = ofPathToString(currentVideoDirectory.path()); +// cout << path << endl; +// std::cout << 3 << std::endl; +// std::string pathEnd("data/../../../video/"); +// std::cout << 4 << std::endl; +// ofxTestEq(path.substr(path.size()-pathEnd.size()), pathEnd, "#4564"); +// std::cout << 5 << std::endl; +// } } }; @@ -283,10 +297,11 @@ class ofApp: public ofxUnitTestsApp{ #include "ofAppRunner.h" //======================================================================== int main( ){ - initial_cwd = of::filesystem::current_path(); ofInit(); + initial_cwd = of::filesystem::current_path(); +// std::cout << "initial_cwd " << initial_cwd << std::endl; auto window = std::make_shared(); auto app = std::make_shared(); ofRunApp(window, app); return ofRunMainLoop(); -} \ No newline at end of file +} diff --git a/tests/utils/xml/bin/data/.gitkeep b/tests/utils/xml/bin/data/.gitkeep new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/utils/xml/bin/data/.gitkeep @@ -0,0 +1 @@ +