mirror of
https://github.com/NixOS/nix
synced 2025-06-25 06:31:14 +02:00
add DirectoryIterator to re-throw std::filesystem::filesystem_error
Co-authored-by: Sergei Zimmerman <145775305+xokdvium@users.noreply.github.com>
This commit is contained in:
parent
4548dd1abb
commit
7ccc0d591f
3 changed files with 109 additions and 0 deletions
|
@ -297,4 +297,25 @@ TEST(chmodIfNeeded, nonexistent)
|
|||
ASSERT_THROW(chmodIfNeeded("/schnitzel/darmstadt/pommes", 0755), SysError);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* DirectoryIterator
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(DirectoryIterator, works)
|
||||
{
|
||||
auto tmpDir = nix::createTempDir();
|
||||
nix::AutoDelete delTmpDir(tmpDir, true);
|
||||
|
||||
nix::writeFile(tmpDir + "/somefile", "");
|
||||
|
||||
for (auto path : DirectoryIterator(tmpDir)) {
|
||||
ASSERT_EQ(path.path().string(), tmpDir + "/somefile");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DirectoryIterator, nonexistent)
|
||||
{
|
||||
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SysError);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,34 @@ namespace fs {
|
|||
}
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator(const std::filesystem::path& p) {
|
||||
try {
|
||||
// **Attempt to create the underlying directory_iterator**
|
||||
it_ = std::filesystem::directory_iterator(p);
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
// **Catch filesystem_error and throw SysError**
|
||||
// Adapt the error message as needed for SysError
|
||||
throw SysError("cannot read directory %s", p);
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryIterator& DirectoryIterator::operator++() {
|
||||
// **Attempt to increment the underlying iterator**
|
||||
std::error_code ec;
|
||||
it_.increment(ec);
|
||||
if (ec) {
|
||||
// Try to get path info if possible, might fail if iterator is bad
|
||||
try {
|
||||
if (it_ != std::filesystem::directory_iterator{}) {
|
||||
throw SysError("cannot read directory past %s: %s", it_->path(), ec.message());
|
||||
}
|
||||
} catch (...) {
|
||||
throw SysError("cannot read directory");
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isAbsolute(PathView path)
|
||||
{
|
||||
return fs::path { path }.is_absolute();
|
||||
|
|
|
@ -376,4 +376,64 @@ extern PathFilter defaultPathFilter;
|
|||
*/
|
||||
bool chmodIfNeeded(const std::filesystem::path & path, mode_t mode, mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
|
||||
/**
|
||||
* @brief A directory iterator that can be used to iterate over the
|
||||
* contents of a directory. It is similar to std::filesystem::directory_iterator
|
||||
* but throws NixError on failure instead of std::filesystem::filesystem_error.
|
||||
*/
|
||||
class DirectoryIterator {
|
||||
public:
|
||||
// --- Iterator Traits ---
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = std::filesystem::directory_entry;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const std::filesystem::directory_entry*;
|
||||
using reference = const std::filesystem::directory_entry&;
|
||||
|
||||
// Default constructor (represents end iterator)
|
||||
DirectoryIterator() noexcept = default;
|
||||
|
||||
// Constructor taking a path
|
||||
explicit DirectoryIterator(const std::filesystem::path& p);
|
||||
|
||||
reference operator*() const {
|
||||
// Accessing the value itself doesn't typically throw filesystem_error
|
||||
// after successful construction/increment, but underlying operations might.
|
||||
// If directory_entry methods called via -> could throw, add try-catch there.
|
||||
return *it_;
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
return &(*it_);
|
||||
}
|
||||
|
||||
|
||||
DirectoryIterator& operator++();
|
||||
|
||||
// Postfix increment operator
|
||||
DirectoryIterator operator++(int) {
|
||||
DirectoryIterator temp = *this;
|
||||
++(*this); // Uses the prefix increment's try-catch logic
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Equality comparison
|
||||
friend bool operator==(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
|
||||
return a.it_ == b.it_;
|
||||
}
|
||||
|
||||
// Inequality comparison
|
||||
friend bool operator!=(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Allow direct use in range-based for loops if iterating over an instance
|
||||
DirectoryIterator begin() const { return *this; }
|
||||
DirectoryIterator end() const { return DirectoryIterator{}; }
|
||||
|
||||
|
||||
private:
|
||||
std::filesystem::directory_iterator it_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue