Add --status and --status-interval.

--status prints a status message to stderr at regular intervals.
--status-interval sets the interval for status messages.

Closes: #10
This commit is contained in:
tastytea 2021-06-24 18:06:11 +02:00
parent 1cf6306f4b
commit 961deff41d
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
4 changed files with 54 additions and 6 deletions

View File

@ -38,6 +38,12 @@ epubgrep -PiC2 '(Apple|Orange)s?' file.epub
epubgrep -PC0 --raw --no-filename=all '"http[^"]+"' file.epub | tr -d '"'
--------------------------------------------------------------------------------
.Save the search results to an HTML file and output a status message every 20 seconds
[source,shell]
--------------------------------------------------------------------------------
epubgrep -C2 --status --status-interval=20 --html 'Apples' file.epub > result.html
--------------------------------------------------------------------------------
== OPTIONS
*-h*, *--help*::
@ -109,6 +115,12 @@ in an array named `matches`. I will try not to break the API. 😊
Output HTML instead of plain text. HTML will only be output at the end of the
program.
*--status*::
Output status message every *--status-interval* seconds to standard error.
*--status-interval* _NUMBER_::
Set status message interval to _NUMBER_ seconds.
== USAGE
[source,shellsession]

View File

@ -28,6 +28,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h> // For compatibility with fmt 4.
#include <chrono>
#include <clocale>
#include <cmath>
#include <cstdint>
@ -141,6 +142,7 @@ int main(int argc, char *argv[])
vector<vector<search::match>> matches_all;
std::mutex mutex_matches_all;
vector<std::future<int>> futurepool;
std::atomic<size_t> books_searched{0};
auto search_file{
[&opts, &matches_all, &mutex_matches_all,
@ -188,7 +190,7 @@ int main(int argc, char *argv[])
}};
auto futures_cleanup{
[&futurepool, &return_code](const bool wait = false)
[&futurepool, &return_code, &books_searched](const bool wait = false)
{
using namespace std::chrono_literals;
@ -208,6 +210,7 @@ int main(int argc, char *argv[])
}
}
futurepool.erase(it);
++books_searched;
}
}};
@ -219,6 +222,26 @@ int main(int argc, char *argv[])
}()};
DEBUGLOG << "max_threads = " << max_threads;
const auto print_status{
[&opts, &books_searched, &input_files](std::future<bool> cancel)
{
if (!opts.status)
{
return;
}
while (cancel.wait_for(std::chrono::seconds(opts.status_interval))
!= std::future_status::ready)
{
std::cerr
<< format(translate("{0:d} of {1:d} books searched.").str(),
books_searched, input_files.size())
<< '\n';
}
std::cerr << translate("All books searched.") << '\n';
}};
std::promise<bool> promise_status;
std::thread thread_status{print_status, promise_status.get_future()};
for (const auto &filepath : input_files)
{
while (futurepool.size() >= max_threads)
@ -244,6 +267,8 @@ int main(int argc, char *argv[])
}
DEBUGLOG << "Waiting for remaining threads to finish";
futures_cleanup(true);
promise_status.set_value(true);
thread_status.join();
if (return_code == EXIT_FATAL)
{
return EXIT_FATAL;

View File

@ -88,15 +88,22 @@ options parse_options(int argc, char *argv[])
.str().data())
("dereference-recursive,R",
translate("Read all files under each directory, recursively, "
"following symlinks.") .str().data())
"following symlinks.").str().data())
("ignore-archive-errors",
translate("Ignore errors about wrong file formats.") .str().data())
translate("Ignore errors about wrong file formats.").str().data())
("debug",
translate("Enable debug output.") .str().data())
translate("Enable debug output.").str().data())
("json",
translate("Output JSON instead of plain text.") .str().data())
translate("Output JSON instead of plain text.").str().data())
("html",
translate("Output HTML instead of plain text.") .str().data())
translate("Output HTML instead of plain text.").str().data())
("status",
translate("Output status message every STATUS-INTERVAL seconds")
.str().data())
("status-interval", po::value<std::uint64_t>()
->value_name(translate("NUMBER"))->default_value(30),
translate("Set status message interval to NUMBER seconds.")
.str().data())
;
po::options_description options_hidden("Hidden options");
@ -238,6 +245,8 @@ options parse_again(const po::variables_map &vm)
opts.debug = vm.count("debug") > 0;
opts.json = vm.count("json") > 0;
opts.html = vm.count("html") > 0;
opts.status = vm.count("status") > 0;
opts.status_interval = vm["status-interval"].as<std::uint64_t>();
if (vm.count("regexp") > 0)
{

View File

@ -59,6 +59,8 @@ struct options
bool debug{false};
bool json{false};
bool html{false};
bool status{false};
uint64_t status_interval{0};
//! For the debug output.
friend std::ostream &operator<<(std::ostream &out, const options &opts);