aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2016-02-14 20:52:29 +0100
committerAdrian Kummerlaender2016-02-14 20:52:29 +0100
commit1ffaf37388cd691e88196b6e00455eda0e652cf0 (patch)
treedb1109d7528d4ac563ca61dd28eb35e1ee78c649
parentf8eecef184c8684a3ed27712ccf8f7f866d47c40 (diff)
downloadchange-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar.gz
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar.bz2
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar.lz
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar.xz
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.tar.zst
change-1ffaf37388cd691e88196b6e00455eda0e652cf0.zip
Implement support for excluding arbitrary paths from tracking
The library may be provided with a new-line separated list of regular expressions via the newly introduced `CHANGE_LOG_IGNORE_PATTERN_PATH`. Any proposed tracking path that is matched by any of the provided patterns is excluded from change reporting. This functionality uses the Standard's regular expression parsing functionality and as such doesn't introduce any new dependencies. If no file path is provided or the provided file path is unreadable all paths will be tracked. `change` was adapted to set `CHANGE_LOG_IGNORE_PATTERN_PATH` to `.change_log_ignore` which means that it will by default exclude any patterns provided via this file in the current working directory. An example for such a file customized for hiding _vim_'s internal write logic may look as follows: [0-9]+ [^~]*~ [.*\.viminfo .*\.swp Note that this is implemented in a fashion where it is not guaranteed that the full _canonical_ path is checked against the patterns. It remains to be decided if this is enough for all common use cases of this new functionality. `tracking::PathMatcher` lacks any explicit thread synchronization - according to my current knowledge this should not be necessary as we are only ever reading the private `std::vector<std::regex>` instance. If invalid regular expressions are provided they are silently ignored.
-rw-r--r--CMakeLists.txt1
-rwxr-xr-xchange1
-rw-r--r--src/change_log.cc28
-rw-r--r--src/tracking/change_tracker.cc2
-rw-r--r--src/tracking/path_matcher.cc39
-rw-r--r--src/tracking/path_matcher.h22
6 files changed, 88 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eef9ff4..be9e91e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,6 +15,7 @@ add_library(
SHARED
src/change_log.cc
src/utility/logger.cc
+ src/tracking/path_matcher.cc
src/tracking/change_tracker.cc
)
diff --git a/change b/change
index 344a650..c53dadb 100755
--- a/change
+++ b/change
@@ -1,6 +1,7 @@
#!/usr/bin/bash
export CHANGE_LOG_TARGET="/tmp/$(basename $0).$$.tmp"
+export CHANGE_LOG_IGNORE_PATTERN_PATH=".change_log_ignore"
LD_PRELOAD=libChangeLog.so eval "$@"
diff --git a/src/change_log.cc b/src/change_log.cc
index a00a26f..f1279d2 100644
--- a/src/change_log.cc
+++ b/src/change_log.cc
@@ -2,6 +2,7 @@
#include "utility/io.h"
#include "utility/logger.h"
+#include "tracking/path_matcher.h"
#include "tracking/change_tracker.h"
// `true` signals the interposed functions to execute tracking logic
@@ -10,6 +11,7 @@ static bool enabled = false;
static std::unique_ptr<utility::FileDescriptorGuard> fd_guard;
static std::unique_ptr<utility::Logger> logger;
+static std::unique_ptr<tracking::PathMatcher> matcher;
static std::unique_ptr<tracking::ChangeTracker> tracker;
void init() __attribute__ ((constructor));
@@ -31,6 +33,14 @@ void init() {
tracker = std::make_unique<tracking::ChangeTracker>(logger.get());
}
+ if ( getenv("CHANGE_LOG_IGNORE_PATTERN_PATH") != NULL ) {
+ matcher = std::make_unique<tracking::PathMatcher>(
+ getenv("CHANGE_LOG_IGNORE_PATTERN_PATH")
+ );
+ } else {
+ matcher = std::make_unique<tracking::PathMatcher>();
+ }
+
// tracking is only enabled when everything is initialized as both
// the actual tracking and the decision if a event should be tracked
// depend on `logger` and `tracker` being fully instantiated.
@@ -42,22 +52,32 @@ void init() {
inline void track_write(const int fd) {
if ( enabled && fd != *fd_guard && utility::is_regular_file(fd) ) {
- tracker->track(utility::get_file_path(fd));
+ const auto path = utility::get_file_path(fd);
+
+ if ( !matcher->isMatching(path) ) {
+ tracker->track(path);
+ }
}
}
inline void track_rename(
const std::string& old_path, const std::string& new_path) {
if ( enabled ) {
- tracker->track(old_path);
+ if ( !matcher->isMatching(old_path) ) {
+ tracker->track(old_path);
- logger->append("renamed '", old_path, "' to '", new_path, "'");
+ if ( !matcher->isMatching(new_path) ) {
+ logger->append("renamed '", old_path, "' to '", new_path, "'");
+ }
+ }
}
}
inline void track_remove(const std::string& path) {
if ( enabled && utility::is_regular_file(path.c_str()) ) {
- logger->append("removed '", path, "'");
+ if ( !matcher->isMatching(path) ) {
+ logger->append("removed '", path, "'");
+ }
}
}
diff --git a/src/tracking/change_tracker.cc b/src/tracking/change_tracker.cc
index df91be0..9eab5a2 100644
--- a/src/tracking/change_tracker.cc
+++ b/src/tracking/change_tracker.cc
@@ -125,7 +125,7 @@ void ChangeTracker::track(const std::string& file_path) {
if ( std::get<EMPLACE_SUCCESS>(result) ) {
read_file_to_stream(
- full_path,
+ full_path,
std::get<FILE_CONTENT>(*result.first).get()
);
}
diff --git a/src/tracking/path_matcher.cc b/src/tracking/path_matcher.cc
new file mode 100644
index 0000000..e754586
--- /dev/null
+++ b/src/tracking/path_matcher.cc
@@ -0,0 +1,39 @@
+#include "path_matcher.h"
+
+#include <algorithm>
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+namespace tracking {
+
+PathMatcher::PathMatcher(const std::string& source_file_path) {
+ try {
+ boost::filesystem::ifstream file(source_file_path);
+
+ if ( file.is_open() ) {
+ std::string current_line;
+
+ while ( std::getline(file, current_line) ) {
+ try {
+ this->patterns_.emplace_back(current_line);
+ } catch ( const std::regex_error& ) { }
+ }
+ }
+ } catch ( boost::filesystem::filesystem_error& ) {
+ // invalid source path is not relevant as we can easily fall back to declining
+ // all candidate paths.
+ }
+}
+
+bool PathMatcher::isMatching(const std::string& candidate) const {
+ return std::any_of(
+ this->patterns_.begin(),
+ this->patterns_.end(),
+ [&candidate](const std::regex& pattern) -> bool {
+ return std::regex_match(candidate, pattern);
+ }
+ );
+}
+
+}
diff --git a/src/tracking/path_matcher.h b/src/tracking/path_matcher.h
new file mode 100644
index 0000000..64337c0
--- /dev/null
+++ b/src/tracking/path_matcher.h
@@ -0,0 +1,22 @@
+#ifndef CHANGE_SRC_TRACKING_PATH_MATCHER_H_
+#define CHANGE_SRC_TRACKING_PATH_MATCHER_H_
+
+#include <regex>
+#include <vector>
+
+namespace tracking {
+
+class PathMatcher {
+ public:
+ PathMatcher() = default;
+ PathMatcher(const std::string&);
+
+ bool isMatching(const std::string&) const;
+
+ private:
+ std::vector<std::regex> patterns_;
+};
+
+}
+
+#endif // CHANGE_SRC_TRACKING_PATH_MATCHER_H_