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:
parent
1cf6306f4b
commit
961deff41d
|
@ -38,6 +38,12 @@ epubgrep -PiC2 '(Apple|Orange)s?' file.epub
|
||||||
epubgrep -PC0 --raw --no-filename=all '"http[^"]+"' file.epub | tr -d '"'
|
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
|
== OPTIONS
|
||||||
|
|
||||||
*-h*, *--help*::
|
*-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
|
Output HTML instead of plain text. HTML will only be output at the end of the
|
||||||
program.
|
program.
|
||||||
|
|
||||||
|
*--status*::
|
||||||
|
Output status message every *--status-interval* seconds to standard error.
|
||||||
|
|
||||||
|
*--status-interval* _NUMBER_::
|
||||||
|
Set status message interval to _NUMBER_ seconds.
|
||||||
|
|
||||||
== USAGE
|
== USAGE
|
||||||
|
|
||||||
[source,shellsession]
|
[source,shellsession]
|
||||||
|
|
27
src/main.cpp
27
src/main.cpp
|
@ -28,6 +28,7 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fmt/ostream.h> // For compatibility with fmt 4.
|
#include <fmt/ostream.h> // For compatibility with fmt 4.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -141,6 +142,7 @@ int main(int argc, char *argv[])
|
||||||
vector<vector<search::match>> matches_all;
|
vector<vector<search::match>> matches_all;
|
||||||
std::mutex mutex_matches_all;
|
std::mutex mutex_matches_all;
|
||||||
vector<std::future<int>> futurepool;
|
vector<std::future<int>> futurepool;
|
||||||
|
std::atomic<size_t> books_searched{0};
|
||||||
|
|
||||||
auto search_file{
|
auto search_file{
|
||||||
[&opts, &matches_all, &mutex_matches_all,
|
[&opts, &matches_all, &mutex_matches_all,
|
||||||
|
@ -188,7 +190,7 @@ int main(int argc, char *argv[])
|
||||||
}};
|
}};
|
||||||
|
|
||||||
auto futures_cleanup{
|
auto futures_cleanup{
|
||||||
[&futurepool, &return_code](const bool wait = false)
|
[&futurepool, &return_code, &books_searched](const bool wait = false)
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
@ -208,6 +210,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
futurepool.erase(it);
|
futurepool.erase(it);
|
||||||
|
++books_searched;
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
@ -219,6 +222,26 @@ int main(int argc, char *argv[])
|
||||||
}()};
|
}()};
|
||||||
DEBUGLOG << "max_threads = " << max_threads;
|
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)
|
for (const auto &filepath : input_files)
|
||||||
{
|
{
|
||||||
while (futurepool.size() >= max_threads)
|
while (futurepool.size() >= max_threads)
|
||||||
|
@ -244,6 +267,8 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
DEBUGLOG << "Waiting for remaining threads to finish";
|
DEBUGLOG << "Waiting for remaining threads to finish";
|
||||||
futures_cleanup(true);
|
futures_cleanup(true);
|
||||||
|
promise_status.set_value(true);
|
||||||
|
thread_status.join();
|
||||||
if (return_code == EXIT_FATAL)
|
if (return_code == EXIT_FATAL)
|
||||||
{
|
{
|
||||||
return EXIT_FATAL;
|
return EXIT_FATAL;
|
||||||
|
|
|
@ -88,15 +88,22 @@ options parse_options(int argc, char *argv[])
|
||||||
.str().data())
|
.str().data())
|
||||||
("dereference-recursive,R",
|
("dereference-recursive,R",
|
||||||
translate("Read all files under each directory, recursively, "
|
translate("Read all files under each directory, recursively, "
|
||||||
"following symlinks.") .str().data())
|
"following symlinks.").str().data())
|
||||||
("ignore-archive-errors",
|
("ignore-archive-errors",
|
||||||
translate("Ignore errors about wrong file formats.") .str().data())
|
translate("Ignore errors about wrong file formats.").str().data())
|
||||||
("debug",
|
("debug",
|
||||||
translate("Enable debug output.") .str().data())
|
translate("Enable debug output.").str().data())
|
||||||
("json",
|
("json",
|
||||||
translate("Output JSON instead of plain text.") .str().data())
|
translate("Output JSON instead of plain text.").str().data())
|
||||||
("html",
|
("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");
|
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.debug = vm.count("debug") > 0;
|
||||||
opts.json = vm.count("json") > 0;
|
opts.json = vm.count("json") > 0;
|
||||||
opts.html = vm.count("html") > 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)
|
if (vm.count("regexp") > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,6 +59,8 @@ struct options
|
||||||
bool debug{false};
|
bool debug{false};
|
||||||
bool json{false};
|
bool json{false};
|
||||||
bool html{false};
|
bool html{false};
|
||||||
|
bool status{false};
|
||||||
|
uint64_t status_interval{0};
|
||||||
|
|
||||||
//! For the debug output.
|
//! For the debug output.
|
||||||
friend std::ostream &operator<<(std::ostream &out, const options &opts);
|
friend std::ostream &operator<<(std::ostream &out, const options &opts);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user