7using namespace std::literals;
12void log_path(
const fs::path& )
32 for(
const auto& e : rhs.
entries)
37 auto created_sz_before =
created.size();
40 created.emplace_back(created_sz_before + idx);
43 auto modified_sz_before =
modified.size();
46 modified.emplace_back(modified_sz_before + idx);
53 for(
auto& e : rhs.entries)
55 entries.emplace_back(std::move(e));
58 auto created_sz_before =
created.size();
59 for(
auto idx : rhs.created)
61 created.emplace_back(created_sz_before + idx);
64 auto modified_sz_before =
modified.size();
65 for(
auto idx : rhs.modified)
67 modified.emplace_back(modified_sz_before + idx);
85 clock_t::duration poll_interval,
97 for(
auto&
entry : fs::recursive_directory_iterator(
root_, err))
106 for(
auto&
entry : fs::directory_iterator(
root_, err))
153 for(
auto&
entry : fs::recursive_directory_iterator(
root_, err))
162 for(
auto&
entry : fs::directory_iterator(
root_, err))
185 static auto get_original_path(
const fs::path& old_path,
const fs::path& renamed_path,
const fs::path& new_path) -> fs::path
187 fs::path relative_path = fs::relative(new_path, renamed_path);
188 fs::path original_path = old_path / relative_path;
189 return original_path;
194 bool same_extensions =
true;
199 while(ep.has_extension() || fp.has_extension())
201 same_extensions &= ep.extension() == fp.extension();
206 return same_extensions;
212 for(
const auto& renamed_idx : renamed_dirs)
214 const auto& renamed_e = entries[renamed_idx];
229 template<
typename Container>
233 auto it = std::begin(container);
234 while(it != std::end(container))
236 auto& fi = it->second;
238 if(!fs::exists(fi.path, err))
241 if(e.size == fi.size)
243 auto diff = (e.last_mod_time - fi.last_mod_time);
244 auto d = std::chrono::duration_cast<std::chrono::milliseconds>(diff);
246 if(d <= std::chrono::milliseconds(0))
252 e.last_path = fi.path;
271 template<
typename Container>
275 auto it = std::begin(container);
276 while(it != std::end(container))
278 auto& fi = it->second;
280 if(!fs::exists(fi.path, err))
283 entries.push_back(fi);
285 it = container.erase(it);
295 template<
typename Container>
299 using namespace std::literals;
302 std::vector<size_t> renamed_dirs;
304 for(
auto idx : changes.
created)
306 auto& e = changes.
entries[idx];
313 old_entries.erase(e.last_path.string());
320 if(e.type == fs::file_type::directory)
322 renamed_dirs.emplace_back(idx);
344 auto time = fs::last_write_time(path, err);
345 auto size = fs::file_size(path, err);
346 fs::file_status status = fs::status(path, err);
348 std::string key = path.string();
352 auto& fi = it->second;
354 if(fi.last_mod_time != time || fi.size !=
size || fi.type != status.type())
357 fi.last_mod_time = time;
359 fi.type = status.type();
366 fi.type = status.type();
375 fi.last_mod_time = time;
378 fi.type = status.type();
409static auto get_watcher() ->
watcher&
420 clock_t::duration poll_interval,
423 return watch_impl(path, filter, recursive, initial_list, poll_interval, callback);
436void watcher::touch(
const fs::path& path,
bool recursive, fs::file_time_type time)
439 if(fs::exists(path, err))
441 if(fs::is_directory(path, err))
445 for(
auto&
entry : fs::recursive_directory_iterator(path, err))
447 fs::last_write_time(
entry.path(), time, err);
452 for(
auto&
entry : fs::directory_iterator(path, err))
454 fs::last_write_time(
entry.path(), time, err);
458 fs::last_write_time(path, time, err);
462 fs::last_write_time(path, time, err);
477 auto& wd = get_watcher();
480 std::lock_guard<std::mutex> lock(wd.mutex_);
481 for(
auto& kvp : wd.watchers_)
483 auto& w = kvp.second;
493 auto& wd = get_watcher();
496 std::lock_guard<std::mutex> lock(wd.mutex_);
497 for(
auto& kvp : wd.watchers_)
499 auto& w = kvp.second;
527 using namespace std::literals;
530 clock_t::duration sleep_time = 99999h;
533 std::map<std::uint64_t, std::shared_ptr<impl>> watchers;
535 std::unique_lock<std::mutex> lock(
mutex_);
539 for(
auto& pair : watchers)
543 auto now = clock_t::now();
545 auto diff = (
watcher->last_poll_ +
watcher->poll_interval_) - now;
546 if(diff <= clock_t::duration(0))
551 sleep_time = std::min(sleep_time,
watcher->poll_interval_);
555 sleep_time = std::min(sleep_time, diff);
559 std::unique_lock<std::mutex> lock(
mutex_);
560 cv_.wait_for(lock, sleep_time);
569 clock_t::duration poll_interval,
572 auto& wd = get_watcher();
582 static std::atomic<std::uint64_t> free_id = {1};
583 auto key = free_id++;
585 auto imp = std::make_shared<impl>(path, filter, recursive, initial_list, poll_interval, std::move(list_callback));
586 std::lock_guard<std::mutex> lock(wd.mutex_);
587 wd.watchers_.emplace(key, std::move(imp));
598 auto& wd = get_watcher();
601 std::lock_guard<std::mutex> lock(wd.mutex_);
602 wd.watchers_.erase(key);
609 auto& wd = get_watcher();
611 std::lock_guard<std::mutex> lock(wd.mutex_);
612 wd.watchers_.clear();
619 static auto file_type_to_string = [](file_type
type) -> std::string
623 case file_type::regular:
625 case file_type::directory:
649 std::stringstream ss;
650 ss <<
"{\"" << int64_t(e.last_mod_time.time_since_epoch().count()) <<
"\":[" << e.path <<
"," << file_type_to_string(e.type)
651 <<
"," << status_to_string(e.status) <<
"]}";
A filter that combines include and exclude patterns for file/directory filtering.
auto should_include(const fs::path &path) const -> bool
Tests if a path should be included based on the filter rules Logic: (matches any include pattern OR n...
pattern_filter filter_
Filter applied.
clock_t::duration poll_interval_
clock_t::time_point last_poll_
static auto check_if_same_extension(const fs::path &p1, const fs::path &p2) -> bool
static auto check_if_parent_dir_was_renamed(const std::vector< size_t > &renamed_dirs, const std::vector< watcher::entry > &entries, entry &e) -> bool
fs::path root_
Path to watch.
notify_callback callback_
Callback for list of modifications.
static void check_for_removed(std::vector< watcher::entry > &entries, Container &container)
static auto check_if_renamed(entry &e, Container &container) -> bool
std::atomic< bool > paused_
std::map< std::string, watcher::entry > entries_
Cache watched files.
impl(const fs::path &path, const pattern_filter &filter, bool recursive, bool initial_list, clock_t::duration poll_interval, notify_callback list_callback)
observed_changes buffered_changes_
void poll_entry(const fs::path &path, observed_changes &changes)
static auto get_original_path(const fs::path &old_path, const fs::path &renamed_path, const fs::path &new_path) -> fs::path
static void process_modifications(Container &old_entries, observed_changes &changes)
static void unwatch_impl(std::uint64_t key)
static void unwatch(std::uint64_t key)
Un-watches a previously registered file or directory.
static void unwatch_all_impl()
std::function< void(const std::vector< entry > &, bool)> notify_callback
std::atomic< bool > watching_
Atomic bool sync.
static void unwatch_all()
Un-watches all previously registered file or directory.
static void touch(const fs::path &path, bool recursive, fs::file_time_type time=fs::now())
Sets the last modification time of a file or directory. by default sets the time to the current time.
std::condition_variable cv_
std::map< std::uint64_t, std::shared_ptr< impl > > watchers_
static auto watch_impl(const fs::path &path, const pattern_filter &filter, bool recursive, bool initial_list, clock_t::duration poll_interval, notify_callback &list_callback) -> std::uint64_t
std::thread thread_
Thread that polls for changes.
std::mutex mutex_
Mutex for the file watchers.
static auto watch(const fs::path &path, const pattern_filter &filter, bool recursive, bool initial_list, clock_t::duration poll_interval, notify_callback callback) -> std::uint64_t
Watches a file or directory for modification and call back the specified std::function....
bool is_any_parent_path(const path &parent, const path &child)
auto to_string(const watcher::entry &e) -> std::string
void append(const observed_changes &rhs)
std::vector< size_t > created
std::vector< size_t > modified
std::vector< watcher::entry > entries
void append(observed_changes &&rhs)