From cce63aca270c51fb3ce9790438e3c23864de0a87 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Wed, 23 Dec 2015 21:43:51 +0100 Subject: Implement file change tracking using `diff` The newly introduced `ChangeTracker` class is now keeping track of all tracked file in addition to spawning and managing a corresponding `diff` instance that enables printing pretty _patch-style_ change summaries to the logging target. This commit introduces `boost-process` and `diff` as dependencies of this library. --- src/change_tracker.cc | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/change_tracker.cc (limited to 'src/change_tracker.cc') diff --git a/src/change_tracker.cc b/src/change_tracker.cc new file mode 100644 index 0000000..1373a8a --- /dev/null +++ b/src/change_tracker.cc @@ -0,0 +1,94 @@ +#include "change_tracker.h" + +#include + +#include +#include + +namespace { + +// constants for increasing pair access readability +constexpr unsigned int EMPLACE_SUCCESS = 1; +constexpr unsigned int FILE_NAME = 0; +constexpr unsigned int DIFF_PROCESS = 1; + +boost::process::context createContext() { + boost::process::context context; + + context.environment = boost::process::self::get_environment(); + context.stdout_behavior = boost::process::capture_stream(); + context.stdin_behavior = boost::process::capture_stream(); + + return context; +} + +} + +namespace utility { + +ChangeTracker::ChangeTracker(utility::Logger* logger): + logger_(logger), + children_() { } + +ChangeTracker::~ChangeTracker() { + for ( auto&& tracked : this->children_ ) { + std::get(tracked)->get_stdin().close(); + + this->logger_->forward(std::get(tracked)->get_stdout()); + + tracked.second->wait(); + } +} + +bool ChangeTracker::is_tracked(const std::string& file_path) const { + return this->children_.find(file_path) != this->children_.end(); +} + +// Begins tracking changes to a file reachable by a given path +// +// The actual tracking is performed by a `diff` instance that is +// spawned by this method and managed by this class. +// As `diff` is called as a new subprocess and because there is no +// straight forward way for checking / enforcing if it has already +// completed reading the initial contents of the file the command +// is structured in the following sequence: +// +// diff -p - $file_path +// +// This means that reading the final file contents is delegated to +// `diff` while the initial file contents are read by this method +// and written to `diff`'s standard input. +// +// If the `-` and `$file_path` arguments were exchanged there would +// be no way to: +// - be sure the initial contents are read before the changing +// syscall that triggered this tracking in the first place is +// performed +// - be sure that the initial file contents are read completly +// as `diff` seemingly only reads the first block of the first +// file provided if the second file argument is standard input +// +bool ChangeTracker::track(const std::string& file_path) { + auto result = this->children_.emplace( + file_path, + std::make_unique( + boost::process::launch_shell("diff -p - " + file_name, createContext()) + ) + ); + + if ( std::get(result) ) { + boost::filesystem::ifstream file( + std::get(*result.first) + ); + + if ( file.is_open() ) { + std::get(*result.first)->get_stdin() << file.rdbuf(); + } + + return true; + } else { + return false; + } +} + +} -- cgit v1.2.3