Skip to content

Commit

Permalink
enh(File): add absolutePath and existsAnywhere() #4482
Browse files Browse the repository at this point in the history
  • Loading branch information
aleks-f committed Mar 6, 2024
1 parent 42995c2 commit 66d92d8
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 6 deletions.
1 change: 1 addition & 0 deletions Foundation/include/Poco/Exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ POCO_DECLARE_EXCEPTION(Foundation_API, CreateFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, OpenFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, WriteFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, ReadFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, ExecuteFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, FileNotReadyException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, DirectoryNotEmptyException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, UnknownURISchemeException, RuntimeException)
Expand Down
15 changes: 15 additions & 0 deletions Foundation/include/Poco/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,24 @@ class Foundation_API File: private FileImpl
const std::string& path() const;
/// Returns the path.

std::string absolutePath() const;
/// Returns absolute path.
/// Attempts to find the existing file
/// using curent work directory and the PATH
/// environment variable.
/// If the file doesn't exist, returns empty string.

bool exists() const;
/// Returns true iff the file exists.

bool existsAnywhere() const;
/// If the file path is relative, searches
/// for the file in the current working directory
/// and the environment paths.
/// If the file path is absolute, the
/// functionality is identical to the
/// exists() call.

bool canRead() const;
/// Returns true iff the file is readable.

Expand Down
1 change: 1 addition & 0 deletions Foundation/src/Exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ POCO_IMPLEMENT_EXCEPTION(CreateFileException, FileException, "Cannot create file
POCO_IMPLEMENT_EXCEPTION(OpenFileException, FileException, "Cannot open file")
POCO_IMPLEMENT_EXCEPTION(WriteFileException, FileException, "Cannot write file")
POCO_IMPLEMENT_EXCEPTION(ReadFileException, FileException, "Cannot read file")
POCO_IMPLEMENT_EXCEPTION(ExecuteFileException, FileException, "Cannot execute file")
POCO_IMPLEMENT_EXCEPTION(FileNotReadyException, FileException, "File not ready")
POCO_IMPLEMENT_EXCEPTION(DirectoryNotEmptyException, FileException, "Directory not empty")
POCO_IMPLEMENT_EXCEPTION(UnknownURISchemeException, RuntimeException, "Unknown URI scheme")
Expand Down
56 changes: 56 additions & 0 deletions Foundation/src/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "Poco/File.h"
#include "Poco/Path.h"
#include "Poco/DirectoryIterator.h"
#include "Poco/Environment.h"
#include "Poco/StringTokenizer.h"


#if defined(POCO_OS_FAMILY_WINDOWS)
Expand Down Expand Up @@ -95,12 +97,66 @@ void File::swap(File& file) noexcept
}


std::string File::absolutePath() const
{
std::string ret;

if (Path(path()).isAbsolute())
ret = getPathImpl();
else
{
Path curPath(Path::current());
curPath.append(path());
if (File(curPath).exists()) ret = curPath.toString();
else
{
std::string envPath = Environment::get("PATH", "");
std::string pathSeparator(1, Path::pathSeparator());
if (!envPath.empty())
{
StringTokenizer st(envPath, pathSeparator,
StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
for (const auto& p: st)
{
std::string fileName(p);
if (p.size() && p[p.size()-1] != Path::separator())
fileName.append(1, Path::separator());
fileName.append(path());
if (File(fileName).exists())
{
ret = fileName;
break;
}
}
}
}
}

return ret;
}


bool File::exists() const
{
if (path().empty()) return false;
return existsImpl();
}


bool File::existsAnywhere() const
{
if (path().empty()) return false;

if (Path(path()).isAbsolute())
return existsImpl();

if (File(absolutePath()).exists())
return true;

return false;
}


bool File::canRead() const
{
return canReadImpl();
Expand Down
13 changes: 12 additions & 1 deletion Foundation/src/ProcessRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,18 @@ void ProcessRunner::start()
{
if (!_started.exchange(true))
{
File exe(_cmd);
if (!exe.existsAnywhere())
{
throw Poco::FileNotFoundException(
Poco::format("ProcessRunner::start(%s): command not found", _cmd));
}
else if (!File(exe.absolutePath()).canExecute())
{
throw Poco::ExecuteFileException(
Poco::format("ProcessRunner::start(%s): cannot execute", _cmd));
}

int prevRunCnt = runCount();

_t.start(*this);
Expand Down Expand Up @@ -256,7 +268,6 @@ void ProcessRunner::start()
}
else
throw Poco::InvalidAccessException("start() called on started ProcessRunner");
checkStatus("", false);
}


Expand Down
53 changes: 52 additions & 1 deletion Foundation/testsuite/src/FileTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include "Poco/Thread.h"
#include <fstream>
#include <set>

#if defined(POCO_OS_FAMILY_WINDOWS)
#include <Windows.h>
#endif

using Poco::File;
using Poco::TemporaryFile;
Expand Down Expand Up @@ -192,6 +194,54 @@ void FileTest::testCreateFile()
}


void FileTest::testExists()
{
assertFalse (File("").exists());

{
File f("testfile.dat");
f.createFile();
assertTrue (f.exists());
assertTrue (f.existsAnywhere());
assertFalse (f.canExecute());
}

{
File f("/testfile.dat");
assertFalse (f.exists());
assertFalse (f.existsAnywhere());
try
{
f.canExecute();
failmsg("file does not exist - must throw exception");
} catch(const Poco::FileNotFoundException&) {}
}

{
#if defined(POCO_OS_FAMILY_UNIX)
File f("echo");
File f2("/dev/null");
#elif defined(POCO_OS_FAMILY_WINDOWS)
File f("cmd.exe");

std::string buffer(Path::system());
UINT r = GetSystemDirectoryA(buffer.c_str(), buffer.size());
Path p(buffer);
p.makeDirectory().makeAbsolute().makeParent();
buffer = p.toString();
buffer.append("win.ini");
File f2(buffer);
#endif
assertFalse (f.exists());
assertTrue (f.existsAnywhere());
assertTrue (File(f.absolutePath()).canExecute());
assertTrue (f2.exists());
assertTrue (f2.existsAnywhere());
assertFalse (f2.canExecute());
}
}


void FileTest::testFileAttributes2()
{
TemporaryFile f;
Expand Down Expand Up @@ -660,6 +710,7 @@ CppUnit::Test* FileTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileTest");

CppUnit_addTest(pSuite, FileTest, testCreateFile);
CppUnit_addTest(pSuite, FileTest, testExists);
CppUnit_addTest(pSuite, FileTest, testFileAttributes1);
CppUnit_addTest(pSuite, FileTest, testFileAttributes2);
CppUnit_addTest(pSuite, FileTest, testFileAttributes3);
Expand Down
1 change: 1 addition & 0 deletions Foundation/testsuite/src/FileTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class FileTest: public CppUnit::TestCase

void testFileAttributes1();
void testCreateFile();
void testExists();
void testFileAttributes2();
void testFileAttributes3();
void testCompare();
Expand Down
3 changes: 3 additions & 0 deletions Foundation/testsuite/src/PathTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ void PathTest::testParseUnix4()
assertTrue (!p.isDirectory());
assertTrue (p.isFile());
assertTrue (p.toString(Path::PATH_UNIX) == "a/b/c/d");

p.makeDirectory();
assertTrue (p.toString(Path::PATH_UNIX) == "a/b/c/d/");
}


Expand Down
8 changes: 4 additions & 4 deletions Foundation/testsuite/src/ProcessRunnerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ void ProcessRunnerTest::testProcessRunner()
try
{
pr.reset(new ProcessRunner(cmd, args));
fail("ProcessRunner should throw an exception.", __LINE__, __FILE__);
} catch(const Poco::RuntimeException& e) {}
failmsg("ProcessRunner should throw an exception.");
} catch(const Poco::FileException& e) {}
}
assertTrue (!File(pidFile).exists());
}
Expand All @@ -294,8 +294,8 @@ void ProcessRunnerTest::testProcessRunner()
try
{
pr.reset(new ProcessRunner(cmd, args));
fail("ProcessRunner should throw an exception.", __LINE__, __FILE__);
} catch(const Poco::RuntimeException& e) {}
failmsg("ProcessRunner should throw an exception.");
} catch(const Poco::FileException& e) {}
}
assertTrue (!File(pidFile).exists());
}
Expand Down

0 comments on commit 66d92d8

Please sign in to comment.