[yajlpp] flesh things out a bit more

This commit is contained in:
Tim Stack 2022-10-04 21:17:01 -07:00
parent 468358a358
commit faeaf477ab
20 changed files with 286 additions and 454 deletions

View File

@ -453,8 +453,7 @@
"field": { "field": {
"title": "/<format_name>/line-format/field", "title": "/<format_name>/line-format/field",
"description": "The name of the field to substitute at this position", "description": "The name of the field to substitute at this position",
"type": "string", "type": "string"
"minLength": 1
}, },
"default-value": { "default-value": {
"title": "/<format_name>/line-format/default-value", "title": "/<format_name>/line-format/default-value",

View File

@ -232,7 +232,7 @@ extract(const std::string& filename, const extract_cb& cb)
} }
auto arc_lock = lnav::filesystem::file_lock(tmp_path); auto arc_lock = lnav::filesystem::file_lock(tmp_path);
auto lock_guard = lnav::filesystem::file_lock::guard(arc_lock); auto lock_guard = lnav::filesystem::file_lock::guard(&arc_lock);
auto done_path = tmp_path; auto done_path = tmp_path;
done_path += ".done"; done_path += ".done";

View File

@ -166,5 +166,18 @@ stat_file(const ghc::filesystem::path& path)
strerror(errno))); strerror(errno)));
} }
file_lock::file_lock(const ghc::filesystem::path& archive_path)
{
auto lock_path = archive_path;
lock_path += ".lck";
auto open_res
= lnav::filesystem::create_file(lock_path, O_RDWR | O_CLOEXEC, 0600);
if (open_res.isErr()) {
throw std::runtime_error(open_res.unwrapErr());
}
this->lh_fd = open_res.unwrap();
}
} // namespace filesystem } // namespace filesystem
} // namespace lnav } // namespace lnav

View File

@ -82,33 +82,36 @@ class file_lock {
public: public:
class guard { class guard {
public: public:
explicit guard(file_lock& arc_lock) : g_lock(arc_lock) explicit guard(file_lock* arc_lock) : g_lock(arc_lock)
{ {
this->g_lock.lock(); this->g_lock->lock();
}; }
~guard() { this->g_lock.unlock(); }; guard(guard&& other) noexcept
: g_lock(std::exchange(other.g_lock, nullptr))
{
}
~guard()
{
if (this->g_lock != nullptr) {
this->g_lock->unlock();
}
}
guard(const guard&) = delete;
guard& operator=(const guard&) = delete;
guard& operator=(guard&&) = delete;
private: private:
file_lock& g_lock; file_lock* g_lock;
}; };
void lock() const { lockf(this->lh_fd, F_LOCK, 0); } void lock() const { lockf(this->lh_fd, F_LOCK, 0); }
void unlock() const { lockf(this->lh_fd, F_ULOCK, 0); } void unlock() const { lockf(this->lh_fd, F_ULOCK, 0); }
explicit file_lock(const ghc::filesystem::path& archive_path) explicit file_lock(const ghc::filesystem::path& archive_path);
{
auto lock_path = archive_path;
lock_path += ".lck";
auto open_res = lnav::filesystem::create_file(
lock_path, O_RDWR | O_CLOEXEC, 0600);
if (open_res.isErr()) {
throw std::runtime_error(open_res.unwrapErr());
}
this->lh_fd = open_res.unwrap();
}
auto_fd lh_fd; auto_fd lh_fd;
}; };

View File

@ -79,7 +79,8 @@ sql_dirname(const char* path_in)
text_end = strlen(path_in) - 1; text_end = strlen(path_in) - 1;
while (text_end >= 0 while (text_end >= 0
&& (path_in[text_end] == '/' || path_in[text_end] == '\\')) { && (path_in[text_end] == '/' || path_in[text_end] == '\\'))
{
text_end -= 1; text_end -= 1;
} }
@ -249,7 +250,8 @@ fs_extension_functions(struct FuncDef** basic_funcs,
* TODO: add other functions like normpath, ... * TODO: add other functions like normpath, ...
*/ */
{nullptr}}; {nullptr},
};
*basic_funcs = fs_funcs; *basic_funcs = fs_funcs;
*agg_funcs = nullptr; *agg_funcs = nullptr;

View File

@ -1359,7 +1359,7 @@ line_buffer::enable_cache()
"%d:cache file path: %s", this->lb_fd.get(), cached_file_path.c_str()); "%d:cache file path: %s", this->lb_fd.get(), cached_file_path.c_str());
auto fl = lnav::filesystem::file_lock(cached_file_path); auto fl = lnav::filesystem::file_lock(cached_file_path);
auto guard = lnav::filesystem::file_lock::guard(fl); auto guard = lnav::filesystem::file_lock::guard(&fl);
if (ghc::filesystem::exists(cached_done_path)) { if (ghc::filesystem::exists(cached_done_path)) {
log_info("%d:using existing cache file"); log_info("%d:using existing cache file");

View File

@ -338,11 +338,12 @@ update_installs_from_git()
if (glob(git_formats.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) { if (glob(git_formats.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) {
for (int lpc = 0; lpc < (int) gl->gl_pathc; lpc++) { for (int lpc = 0; lpc < (int) gl->gl_pathc; lpc++) {
char* git_dir = dirname(gl->gl_pathv[lpc]); auto git_dir
= ghc::filesystem::path(gl->gl_pathv[lpc]).parent_path();
printf("Updating formats in %s\n", git_dir); printf("Updating formats in %s\n", git_dir.c_str());
auto pull_cmd auto pull_cmd = fmt::format(FMT_STRING("cd '{}' && git pull"),
= fmt::format(FMT_STRING("cd '{}' && git pull"), git_dir); git_dir.string());
int ret = system(pull_cmd.c_str()); int ret = system(pull_cmd.c_str());
if (ret == -1) { if (ret == -1) {
std::cerr << "Failed to spawn command " std::cerr << "Failed to spawn command "
@ -519,7 +520,7 @@ static const struct json_path_container global_var_handlers = {
paths_out.emplace_back(iter.first); paths_out.emplace_back(iter.first);
} }
}) })
.FOR_FIELD(_lnav_config, lc_global_vars), .for_field(&_lnav_config::lc_global_vars),
}; };
static const struct json_path_container style_config_handlers = static const struct json_path_container style_config_handlers =
@ -868,7 +869,7 @@ static const struct json_path_container highlighter_handlers = {
yajlpp::property_handler("pattern") yajlpp::property_handler("pattern")
.with_synopsis("regular expression") .with_synopsis("regular expression")
.with_description("The regular expression to highlight") .with_description("The regular expression to highlight")
.FOR_FIELD(highlighter_config, hc_regex), .for_field(&highlighter_config::hc_regex),
yajlpp::property_handler("style") yajlpp::property_handler("style")
.with_description( .with_description(
@ -906,7 +907,7 @@ static const struct json_path_container theme_vars_handlers = {
paths_out.emplace_back(iter.first); paths_out.emplace_back(iter.first);
} }
}) })
.FOR_FIELD(lnav_theme, lt_vars), .for_field(&lnav_theme::lt_vars),
}; };
static const struct json_path_container theme_def_handlers = { static const struct json_path_container theme_def_handlers = {

View File

@ -595,7 +595,7 @@ json_array_end(void* ctx)
return 1; return 1;
} }
static struct json_path_container json_log_handlers = { static const struct json_path_container json_log_handlers = {
yajlpp::pattern_property_handler("\\w+") yajlpp::pattern_property_handler("\\w+")
.add_cb(read_json_null) .add_cb(read_json_null)
.add_cb(read_json_bool) .add_cb(read_json_bool)
@ -671,7 +671,7 @@ rewrite_json_double(yajlpp_parse_context* ypc, double val)
return 1; return 1;
} }
static struct json_path_container json_log_rewrite_handlers = { static const struct json_path_container json_log_rewrite_handlers = {
yajlpp::pattern_property_handler("\\w+") yajlpp::pattern_property_handler("\\w+")
.add_cb(rewrite_json_null) .add_cb(rewrite_json_null)
.add_cb(rewrite_json_bool) .add_cb(rewrite_json_bool)

View File

@ -79,10 +79,8 @@ static external_log_format*
ensure_format(const yajlpp_provider_context& ypc, loader_userdata* ud) ensure_format(const yajlpp_provider_context& ypc, loader_userdata* ud)
{ {
const intern_string_t name = ypc.get_substr_i(0); const intern_string_t name = ypc.get_substr_i(0);
std::vector<intern_string_t>* formats = ud->ud_format_names; auto* formats = ud->ud_format_names;
external_log_format* retval; auto* retval = LOG_FORMATS[name].get();
retval = LOG_FORMATS[name].get();
if (retval == nullptr) { if (retval == nullptr) {
LOG_FORMATS[name] = std::make_shared<external_log_format>(name); LOG_FORMATS[name] = std::make_shared<external_log_format>(name);
retval = LOG_FORMATS[name].get(); retval = LOG_FORMATS[name].get();
@ -95,7 +93,8 @@ ensure_format(const yajlpp_provider_context& ypc, loader_userdata* ud)
} }
if (!ud->ud_format_path.empty()) { if (!ud->ud_format_path.empty()) {
auto i_src_path = intern_string::lookup(ud->ud_format_path.string()); const intern_string_t i_src_path
= intern_string::lookup(ud->ud_format_path.string());
auto srcs_iter = retval->elf_format_sources.find(i_src_path); auto srcs_iter = retval->elf_format_sources.find(i_src_path);
if (srcs_iter == retval->elf_format_sources.end()) { if (srcs_iter == retval->elf_format_sources.end()) {
retval->elf_format_source_order.emplace_back(ud->ud_format_path); retval->elf_format_source_order.emplace_back(ud->ud_format_path);
@ -175,7 +174,7 @@ scaling_factor_provider(const yajlpp_provider_context& ypc,
external_log_format::value_def* value_def) external_log_format::value_def* value_def)
{ {
auto scale_name = ypc.get_substr_i(0); auto scale_name = ypc.get_substr_i(0);
scaling_factor& retval = value_def->vd_unit_scaling[scale_name]; auto& retval = value_def->vd_unit_scaling[scale_name];
return &retval; return &retval;
} }
@ -383,7 +382,7 @@ ensure_sample(external_log_format* elf, int index)
static external_log_format::sample* static external_log_format::sample*
sample_provider(const yajlpp_provider_context& ypc, external_log_format* elf) sample_provider(const yajlpp_provider_context& ypc, external_log_format* elf)
{ {
external_log_format::sample& sample = ensure_sample(elf, ypc.ypc_index); auto& sample = ensure_sample(elf, ypc.ypc_index);
return &sample; return &sample;
} }
@ -404,7 +403,7 @@ read_json_constant(yajlpp_parse_context* ypc,
return 1; return 1;
} }
static struct json_path_container pattern_handlers = { static const struct json_path_container pattern_handlers = {
yajlpp::property_handler("pattern") yajlpp::property_handler("pattern")
.with_synopsis("<message-regex>") .with_synopsis("<message-regex>")
.with_description( .with_description(
@ -455,12 +454,11 @@ static const json_path_handler_base::enum_value_t TRANSFORM_ENUM[] = {
json_path_handler_base::ENUM_TERMINATOR, json_path_handler_base::ENUM_TERMINATOR,
}; };
static struct json_path_container line_format_handlers = { static const struct json_path_container line_format_handlers = {
yajlpp::property_handler("field") yajlpp::property_handler("field")
.with_synopsis("<field-name>") .with_synopsis("<field-name>")
.with_description( .with_description(
"The name of the field to substitute at this position") "The name of the field to substitute at this position")
.with_min_length(1)
.for_field(&external_log_format::json_format_element::jfe_value), .for_field(&external_log_format::json_format_element::jfe_value),
yajlpp::property_handler("default-value") yajlpp::property_handler("default-value")
@ -530,22 +528,22 @@ static const json_path_handler_base::enum_value_t SCALE_OP_ENUM[] = {
json_path_handler_base::ENUM_TERMINATOR, json_path_handler_base::ENUM_TERMINATOR,
}; };
static struct json_path_container scaling_factor_handlers = { static const struct json_path_container scaling_factor_handlers = {
yajlpp::pattern_property_handler("op") yajlpp::pattern_property_handler("op")
.with_enum_values(SCALE_OP_ENUM) .with_enum_values(SCALE_OP_ENUM)
.for_field(&scaling_factor::sf_op), .for_field(&scaling_factor::sf_op),
yajlpp::pattern_property_handler("value").FOR_FIELD(scaling_factor, yajlpp::pattern_property_handler("value").for_field(
sf_value), &scaling_factor::sf_value),
}; };
static struct json_path_container scale_handlers = { static const struct json_path_container scale_handlers = {
yajlpp::pattern_property_handler("(?<scale>[^/]+)") yajlpp::pattern_property_handler("(?<scale>[^/]+)")
.with_obj_provider(scaling_factor_provider) .with_obj_provider(scaling_factor_provider)
.with_children(scaling_factor_handlers), .with_children(scaling_factor_handlers),
}; };
static struct json_path_container unit_handlers = { static const struct json_path_container unit_handlers = {
yajlpp::property_handler("field") yajlpp::property_handler("field")
.with_synopsis("<field-name>") .with_synopsis("<field-name>")
.with_description( .with_description(
@ -557,7 +555,7 @@ static struct json_path_container unit_handlers = {
.with_children(scale_handlers), .with_children(scale_handlers),
}; };
static struct json_path_container value_def_handlers = { static const struct json_path_container value_def_handlers = {
yajlpp::property_handler("kind") yajlpp::property_handler("kind")
.with_synopsis("<data-type>") .with_synopsis("<data-type>")
.with_description("The type of data in the field") .with_description("The type of data in the field")
@ -597,7 +595,7 @@ static struct json_path_container value_def_handlers = {
yajlpp::property_handler("action-list#") yajlpp::property_handler("action-list#")
.with_synopsis("<string>") .with_synopsis("<string>")
.with_description("Actions to execute when this field is clicked on") .with_description("Actions to execute when this field is clicked on")
.FOR_FIELD(external_log_format::value_def, vd_action_list), .for_field(&external_log_format::value_def::vd_action_list),
yajlpp::property_handler("rewriter") yajlpp::property_handler("rewriter")
.with_synopsis("<command>") .with_synopsis("<command>")
@ -613,7 +611,7 @@ static struct json_path_container value_def_handlers = {
.for_field(&external_log_format::value_def::vd_description), .for_field(&external_log_format::value_def::vd_description),
}; };
static struct json_path_container highlighter_def_handlers = { static const struct json_path_container highlighter_def_handlers = {
yajlpp::property_handler("pattern") yajlpp::property_handler("pattern")
.with_synopsis("<regex>") .with_synopsis("<regex>")
.with_description( .with_description(
@ -660,7 +658,7 @@ static const json_path_handler_base::enum_value_t LEVEL_ENUM[] = {
json_path_handler_base::ENUM_TERMINATOR, json_path_handler_base::ENUM_TERMINATOR,
}; };
static struct json_path_container sample_handlers = { static const struct json_path_container sample_handlers = {
yajlpp::property_handler("description") yajlpp::property_handler("description")
.with_synopsis("<text>") .with_synopsis("<text>")
.with_description("A description of this sample.") .with_description("A description of this sample.")
@ -685,14 +683,14 @@ static const json_path_handler_base::enum_value_t TYPE_ENUM[] = {
json_path_handler_base::ENUM_TERMINATOR, json_path_handler_base::ENUM_TERMINATOR,
}; };
static struct json_path_container regex_handlers = { static const struct json_path_container regex_handlers = {
yajlpp::pattern_property_handler(R"((?<pattern_name>[^/]+))") yajlpp::pattern_property_handler(R"((?<pattern_name>[^/]+))")
.with_description("The set of patterns used to match log messages") .with_description("The set of patterns used to match log messages")
.with_obj_provider(pattern_provider) .with_obj_provider(pattern_provider)
.with_children(pattern_handlers), .with_children(pattern_handlers),
}; };
static struct json_path_container level_handlers = { static const struct json_path_container level_handlers = {
yajlpp::pattern_property_handler("(?<level>trace|debug[2345]?|info|stats|" yajlpp::pattern_property_handler("(?<level>trace|debug[2345]?|info|stats|"
"notice|warning|error|critical|fatal)") "notice|warning|error|critical|fatal)")
.add_cb(read_levels) .add_cb(read_levels)
@ -704,7 +702,7 @@ static struct json_path_container level_handlers = {
"the number for the corresponding level."), "the number for the corresponding level."),
}; };
static struct json_path_container value_handlers = { static const struct json_path_container value_handlers = {
yajlpp::pattern_property_handler("(?<value_name>[^/]+)") yajlpp::pattern_property_handler("(?<value_name>[^/]+)")
.with_description( .with_description(
"The set of values captured by the log message patterns") "The set of values captured by the log message patterns")
@ -712,7 +710,7 @@ static struct json_path_container value_handlers = {
.with_children(value_def_handlers), .with_children(value_def_handlers),
}; };
static struct json_path_container tag_path_handlers = { static const struct json_path_container tag_path_handlers = {
yajlpp::property_handler("glob") yajlpp::property_handler("glob")
.with_synopsis("<glob>") .with_synopsis("<glob>")
.with_description("The glob to match against file paths") .with_description("The glob to match against file paths")
@ -720,7 +718,7 @@ static struct json_path_container tag_path_handlers = {
.for_field(&format_tag_def::path_restriction::p_glob), .for_field(&format_tag_def::path_restriction::p_glob),
}; };
static struct json_path_container format_tag_def_handlers = { static const struct json_path_container format_tag_def_handlers = {
yajlpp::property_handler("paths#") yajlpp::property_handler("paths#")
.with_description("Restrict tagging to the given paths") .with_description("Restrict tagging to the given paths")
.for_field(&format_tag_def::ftd_paths) .for_field(&format_tag_def::ftd_paths)
@ -742,14 +740,14 @@ static struct json_path_container format_tag_def_handlers = {
.for_field(&format_tag_def::ftd_level), .for_field(&format_tag_def::ftd_level),
}; };
static struct json_path_container tag_handlers = { static const struct json_path_container tag_handlers = {
yajlpp::pattern_property_handler(R"((?<tag_name>[\w:;\._\-]+))") yajlpp::pattern_property_handler(R"((?<tag_name>[\w:;\._\-]+))")
.with_description("The name of the tag to apply") .with_description("The name of the tag to apply")
.with_obj_provider(format_tag_def_provider) .with_obj_provider(format_tag_def_provider)
.with_children(format_tag_def_handlers), .with_children(format_tag_def_handlers),
}; };
static struct json_path_container highlight_handlers = { static const struct json_path_container highlight_handlers = {
yajlpp::pattern_property_handler(R"((?<highlight_name>[^/]+))") yajlpp::pattern_property_handler(R"((?<highlight_name>[^/]+))")
.with_description("The definition of a highlight") .with_description("The definition of a highlight")
.with_obj_provider<external_log_format::highlighter_def, .with_obj_provider<external_log_format::highlighter_def,
@ -763,20 +761,20 @@ static struct json_path_container highlight_handlers = {
.with_children(highlighter_def_handlers), .with_children(highlighter_def_handlers),
}; };
static struct json_path_container action_def_handlers = { static const struct json_path_container action_def_handlers = {
json_path_handler("label", read_action_def), json_path_handler("label", read_action_def),
json_path_handler("capture-output", read_action_bool), json_path_handler("capture-output", read_action_bool),
json_path_handler("cmd#", read_action_cmd), json_path_handler("cmd#", read_action_cmd),
}; };
static struct json_path_container action_handlers = { static const struct json_path_container action_handlers = {
json_path_handler( json_path_handler(
lnav::pcre2pp::code::from_const("(?<action_name>\\w+)").to_shared(), lnav::pcre2pp::code::from_const("(?<action_name>\\w+)").to_shared(),
read_action_def) read_action_def)
.with_children(action_def_handlers), .with_children(action_def_handlers),
}; };
static struct json_path_container search_table_def_handlers = { static const struct json_path_container search_table_def_handlers = {
json_path_handler("pattern") json_path_handler("pattern")
.with_synopsis("<regex>") .with_synopsis("<regex>")
.with_description("The regular expression for this search table.") .with_description("The regular expression for this search table.")
@ -793,7 +791,7 @@ static struct json_path_container search_table_def_handlers = {
.for_field(&external_log_format::search_table_def::std_level), .for_field(&external_log_format::search_table_def::std_level),
}; };
static struct json_path_container search_table_handlers = { static const struct json_path_container search_table_handlers = {
yajlpp::pattern_property_handler("(?<table_name>\\w+)") yajlpp::pattern_property_handler("(?<table_name>\\w+)")
.with_description( .with_description(
"The set of search tables to be automatically defined") "The set of search tables to be automatically defined")
@ -816,7 +814,7 @@ static const json_path_handler_base::enum_value_t MIME_TYPE_ENUM[] = {
json_path_handler_base::ENUM_TERMINATOR, json_path_handler_base::ENUM_TERMINATOR,
}; };
struct json_path_container format_handlers = { const struct json_path_container format_handlers = {
yajlpp::property_handler("regex") yajlpp::property_handler("regex")
.with_description( .with_description(
"The set of regular expressions used to match log messages") "The set of regular expressions used to match log messages")
@ -978,7 +976,7 @@ read_id(yajlpp_parse_context* ypc, const unsigned char* str, size_t len)
return 1; return 1;
} }
struct json_path_container root_format_handler = json_path_container{ const struct json_path_container root_format_handler = json_path_container{
json_path_handler("$schema", read_id) json_path_handler("$schema", read_id)
.with_synopsis("The URI of the schema for this file") .with_synopsis("The URI of the schema for this file")
.with_description("Specifies the type of this file"), .with_description("Specifies the type of this file"),
@ -1034,15 +1032,13 @@ write_sample_file()
struct script_metadata meta; struct script_metadata meta;
auto sf = bsf.to_string_fragment(); auto sf = bsf.to_string_fragment();
auto_fd script_fd; auto_fd script_fd;
struct stat st;
extract_metadata(sf, meta); extract_metadata(sf, meta);
auto path auto path
= fmt::format(FMT_STRING("formats/default/{}.lnav"), meta.sm_name); = fmt::format(FMT_STRING("formats/default/{}.lnav"), meta.sm_name);
auto script_path = lnav::paths::dotlnav() / path; auto script_path = lnav::paths::dotlnav() / path;
if (lnav::filesystem::statp(script_path, &st) == 0 auto stat_res = lnav::filesystem::stat_file(script_path);
&& st.st_size == sf.length()) if (stat_res.isOk() && stat_res.unwrap().st_size == sf.length()) {
{
// Assume it's the right contents and move on... // Assume it's the right contents and move on...
continue; continue;
} }
@ -1167,19 +1163,19 @@ load_from_path(const ghc::filesystem::path& path,
log_info("loading formats from path: %s", format_path.c_str()); log_info("loading formats from path: %s", format_path.c_str());
if (glob(format_path.c_str(), 0, nullptr, gl.inout()) == 0) { if (glob(format_path.c_str(), 0, nullptr, gl.inout()) == 0) {
for (int lpc = 0; lpc < (int) gl->gl_pathc; lpc++) { for (int lpc = 0; lpc < (int) gl->gl_pathc; lpc++) {
const char* base = basename(gl->gl_pathv[lpc]); auto filepath = ghc::filesystem::path(gl->gl_pathv[lpc]);
if (startswith(base, "config.")) { if (startswith(filepath.filename().string(), "config.")) {
log_info(" not loading config as format: %s",
filepath.c_str());
continue; continue;
} }
std::string filename(gl->gl_pathv[lpc]); auto format_list = load_format_file(filepath, errors);
std::vector<intern_string_t> format_list;
format_list = load_format_file(filename, errors);
if (format_list.empty()) { if (format_list.empty()) {
log_warning("Empty format file: %s", filename.c_str()); log_warning("Empty format file: %s", filepath.c_str());
} else { } else {
log_info("contents of format file '%s':", filepath.c_str());
for (auto iter = format_list.begin(); iter != format_list.end(); for (auto iter = format_list.begin(); iter != format_list.end();
++iter) ++iter)
{ {
@ -1217,8 +1213,7 @@ load_formats(const std::vector<ghc::filesystem::path>& extra_paths,
yajl_config(handle, yajl_allow_comments, 1); yajl_config(handle, yajl_allow_comments, 1);
auto sf = bsf.to_string_fragment(); auto sf = bsf.to_string_fragment();
if (ypc_builtin.parse(sf) != yajl_status_ok) { if (ypc_builtin.parse(sf) != yajl_status_ok) {
unsigned char* msg = yajl_get_error( auto* msg = yajl_get_error(handle, 1, sf.udata(), sf.length());
handle, 1, (const unsigned char*) sf.data(), sf.length());
errors.emplace_back( errors.emplace_back(
lnav::console::user_message::error("invalid json") lnav::console::user_message::error("invalid json")
@ -1402,19 +1397,34 @@ extract_metadata(string_fragment contents, struct script_metadata& meta_out)
void void
extract_metadata_from_file(struct script_metadata& meta_inout) extract_metadata_from_file(struct script_metadata& meta_inout)
{ {
auto stat_res = lnav::filesystem::stat_file(meta_inout.sm_path);
if (stat_res.isErr()) {
log_warning("unable to open script: %s -- %s",
meta_inout.sm_path.c_str(),
stat_res.unwrapErr().c_str());
return;
}
auto st = stat_res.unwrap();
if (!S_ISREG(st.st_mode)) {
log_warning("script is not a regular file -- %s",
meta_inout.sm_path.c_str());
return;
}
auto open_res = lnav::filesystem::open_file(meta_inout.sm_path, O_RDONLY);
if (open_res.isErr()) {
log_warning("unable to open script file: %s -- %s",
meta_inout.sm_path.c_str(),
open_res.unwrapErr().c_str());
return;
}
auto fd = open_res.unwrap();
char buffer[8 * 1024]; char buffer[8 * 1024];
auto_mem<FILE> fp(fclose); auto rc = read(fd, buffer, sizeof(buffer));
struct stat st; if (rc > 0) {
extract_metadata(string_fragment::from_bytes(buffer, rc), meta_inout);
if (lnav::filesystem::statp(meta_inout.sm_path, &st) == -1) {
log_warning("unable to open script -- %s", meta_inout.sm_path.c_str());
} else if (!S_ISREG(st.st_mode)) {
log_warning("not a regular file -- %s", meta_inout.sm_path.c_str());
} else if ((fp = fopen(meta_inout.sm_path.c_str(), "r")) != nullptr) {
size_t len;
len = fread(buffer, 1, sizeof(buffer), fp.in());
extract_metadata(string_fragment::from_bytes(buffer, len), meta_inout);
} }
} }

View File

@ -75,7 +75,7 @@ struct available_scripts {
void find_format_scripts(const std::vector<ghc::filesystem::path>& extra_paths, void find_format_scripts(const std::vector<ghc::filesystem::path>& extra_paths,
available_scripts& scripts); available_scripts& scripts);
extern struct json_path_container format_handlers; extern const struct json_path_container format_handlers;
extern struct json_path_container root_format_handler; extern const struct json_path_container root_format_handler;
#endif #endif

View File

@ -1890,12 +1890,12 @@ vt_best_index(sqlite3_vtab* tab, sqlite3_index_info* p_info)
return SQLITE_OK; return SQLITE_OK;
} }
static struct json_path_container tags_handler = { static const struct json_path_container tags_handler = {
json_path_handler("#") json_path_handler("#")
.with_synopsis("tag") .with_synopsis("tag")
.with_description("A tag for the log line") .with_description("A tag for the log line")
.with_pattern(R"(^#[^\s]+$)") .with_pattern(R"(^#[^\s]+$)")
.FOR_FIELD(bookmark_metadata, bm_tags), .for_field(&bookmark_metadata::bm_tags),
}; };
static int static int

View File

@ -153,8 +153,6 @@ logfile::~logfile() {}
bool bool
logfile::exists() const logfile::exists() const
{ {
struct stat st;
if (!this->lf_actual_path) { if (!this->lf_actual_path) {
return true; return true;
} }
@ -163,13 +161,15 @@ logfile::exists() const
return true; return true;
} }
if (lnav::filesystem::statp(this->lf_actual_path.value(), &st) == -1) { auto stat_res = lnav::filesystem::stat_file(this->lf_actual_path.value());
if (stat_res.isErr()) {
log_error("%s: stat failed -- %s", log_error("%s: stat failed -- %s",
this->lf_actual_path.value().c_str(), this->lf_actual_path.value().c_str(),
strerror(errno)); stat_res.unwrapErr().c_str());
return false; return false;
} }
auto st = stat_res.unwrap();
return this->lf_stat.st_dev == st.st_dev return this->lf_stat.st_dev == st.st_dev
&& this->lf_stat.st_ino == st.st_ino && this->lf_stat.st_ino == st.st_ino
&& this->lf_stat.st_size <= st.st_size; && this->lf_stat.st_size <= st.st_size;

View File

@ -862,7 +862,7 @@ read_commands(yajlpp_parse_context* ypc, const unsigned char* str, size_t len)
return 1; return 1;
} }
static struct json_path_container view_def_handlers = { static const struct json_path_container view_def_handlers = {
json_path_handler("top_line", read_top_line), json_path_handler("top_line", read_top_line),
json_path_handler("search", read_current_search), json_path_handler("search", read_current_search),
json_path_handler("word_wrap", read_word_wrap), json_path_handler("word_wrap", read_word_wrap),
@ -870,18 +870,18 @@ static struct json_path_container view_def_handlers = {
json_path_handler("commands#", read_commands), json_path_handler("commands#", read_commands),
}; };
static struct json_path_container view_handlers = { static const struct json_path_container view_handlers = {
yajlpp::pattern_property_handler("([^/]+)").with_children( yajlpp::pattern_property_handler("([^/]+)").with_children(
view_def_handlers), view_def_handlers),
}; };
static struct json_path_container file_state_handlers = { static const struct json_path_container file_state_handlers = {
yajlpp::property_handler("visible") yajlpp::property_handler("visible")
.with_description("Indicates whether the file is visible or not") .with_description("Indicates whether the file is visible or not")
.for_field(&file_state::fs_is_visible), .for_field(&file_state::fs_is_visible),
}; };
static struct json_path_container file_states_handlers = { static const struct json_path_container file_states_handlers = {
yajlpp::pattern_property_handler(R"((?<filename>[^/]+))") yajlpp::pattern_property_handler(R"((?<filename>[^/]+))")
.with_description("Map of file names to file state objects") .with_description("Map of file names to file state objects")
.with_obj_provider<file_state, void>([](const auto& ypc, auto* root) { .with_obj_provider<file_state, void>([](const auto& ypc, auto* root) {
@ -891,7 +891,7 @@ static struct json_path_container file_states_handlers = {
.with_children(file_state_handlers), .with_children(file_state_handlers),
}; };
static struct json_path_container view_info_handlers = { static const struct json_path_container view_info_handlers = {
yajlpp::property_handler("save-time") yajlpp::property_handler("save-time")
.for_field(&session_data_t::sd_save_time), .for_field(&session_data_t::sd_save_time),
yajlpp::property_handler("time-offset") yajlpp::property_handler("time-offset")

View File

@ -269,7 +269,7 @@ tailer::looper::complete_path(const network::path& path)
static std::vector<std::string> static std::vector<std::string>
create_ssh_args_from_config(const std::string& dest) create_ssh_args_from_config(const std::string& dest)
{ {
auto& cfg = injector::get<const tailer::config&>(); const auto& cfg = injector::get<const tailer::config&>();
std::vector<std::string> retval; std::vector<std::string> retval;
retval.emplace_back(cfg.c_ssh_cmd); retval.emplace_back(cfg.c_ssh_cmd);

View File

@ -383,7 +383,7 @@ json_path_handler_base::gen_schema(yajlpp_gen_context& ygc) const
schema.gen("examples"); schema.gen("examples");
yajlpp_array example_array(ygc.ygc_handle); yajlpp_array example_array(ygc.ygc_handle);
for (auto& ex : this->jph_examples) { for (const auto& ex : this->jph_examples) {
example_array.gen(ex); example_array.gen(ex);
} }
} }
@ -1107,7 +1107,7 @@ yajlpp_parse_context::reset(const struct json_path_container* handlers)
} }
void void
yajlpp_parse_context::set_static_handler(json_path_handler_base& jph) yajlpp_parse_context::set_static_handler(const json_path_handler_base& jph)
{ {
this->ypc_path.clear(); this->ypc_path.clear();
this->ypc_path.push_back('/'); this->ypc_path.push_back('/');
@ -1310,6 +1310,40 @@ yajlpp_parse_context::get_snippet() const
.with_line(line_number); .with_line(line_number);
} }
void
json_path_handler_base::validate_string(yajlpp_parse_context& ypc,
string_fragment sf) const
{
if (this->jph_pattern) {
if (!this->jph_pattern->find_in(sf).ignore_error()) {
this->report_pattern_error(&ypc, sf.to_string());
}
}
if (sf.empty() && this->jph_min_length > 0) {
ypc.report_error(lnav::console::user_message::error(
attr_line_t("invalid value for option ")
.append_quoted(lnav::roles::symbol(
ypc.get_full_path().to_string())))
.with_reason("empty values are not allowed")
.with_snippet(ypc.get_snippet())
.with_help(this->get_help_text(&ypc)));
} else if (sf.length() < this->jph_min_length) {
ypc.report_error(
lnav::console::user_message::error(
attr_line_t()
.append_quoted(sf)
.append(" is not a valid value for option ")
.append_quoted(
lnav::roles::symbol(ypc.get_full_path().to_string())))
.with_reason(attr_line_t("value must be at least ")
.append(lnav::roles::number(
fmt::to_string(this->jph_min_length)))
.append(" characters long"))
.with_snippet(ypc.get_snippet())
.with_help(this->get_help_text(&ypc)));
}
}
void void
json_path_handler_base::report_pattern_error(yajlpp_parse_context* ypc, json_path_handler_base::report_pattern_error(yajlpp_parse_context* ypc,
const std::string& value_str) const const std::string& value_str) const
@ -1378,8 +1412,6 @@ void
json_path_handler_base::report_min_value_error(yajlpp_parse_context* ypc, json_path_handler_base::report_min_value_error(yajlpp_parse_context* ypc,
long long value) const long long value) const
{ {
const auto* jph = ypc->ypc_current_handler;
ypc->report_error( ypc->report_error(
lnav::console::user_message::error( lnav::console::user_message::error(
attr_line_t() attr_line_t()
@ -1389,9 +1421,9 @@ json_path_handler_base::report_min_value_error(yajlpp_parse_context* ypc,
lnav::roles::symbol(ypc->get_full_path().to_string()))) lnav::roles::symbol(ypc->get_full_path().to_string())))
.with_reason(attr_line_t("value must be greater than or equal to ") .with_reason(attr_line_t("value must be greater than or equal to ")
.append(lnav::roles::number( .append(lnav::roles::number(
fmt::to_string(jph->jph_min_value)))) fmt::to_string(this->jph_min_value))))
.with_snippet(ypc->get_snippet()) .with_snippet(ypc->get_snippet())
.with_help(jph->get_help_text(ypc))); .with_help(this->get_help_text(ypc)));
} }
void void
@ -1465,7 +1497,7 @@ json_path_container::gen_properties(yajlpp_gen_context& ygc) const
{ {
yajlpp_map properties(ygc.ygc_handle); yajlpp_map properties(ygc.ygc_handle);
for (auto& child_handler : this->jpc_children) { for (const auto& child_handler : this->jpc_children) {
if (child_handler.jph_is_pattern_property) { if (child_handler.jph_is_pattern_property) {
continue; continue;
} }
@ -1529,5 +1561,5 @@ yajlpp_gen::to_string_fragment()
yajl_gen_get_buf(this->yg_handle.in(), &buf, &len); yajl_gen_get_buf(this->yg_handle.in(), &buf, &len);
return string_fragment((const char*) buf, 0, len); return string_fragment::from_bytes(buf, len);
} }

View File

@ -282,10 +282,13 @@ struct json_path_handler_base {
std::function<int(yajlpp_parse_context*)> jph_null_cb; std::function<int(yajlpp_parse_context*)> jph_null_cb;
std::function<int(yajlpp_parse_context*, int)> jph_bool_cb; std::function<int(yajlpp_parse_context*, int)> jph_bool_cb;
std::function<int(yajlpp_parse_context*, long long)> jph_integer_cb; std::function<int(yajlpp_parse_context*, long long)> jph_integer_cb;
std::function<int(yajlpp_parse_context*, double)> jph_double_cb;
std::function<int( std::function<int(
yajlpp_parse_context*, const unsigned char* str, size_t len)> yajlpp_parse_context*, const unsigned char* str, size_t len)>
jph_str_cb; jph_str_cb;
void validate_string(yajlpp_parse_context& ypc, string_fragment sf) const;
void report_pattern_error(yajlpp_parse_context* ypc, void report_pattern_error(yajlpp_parse_context* ypc,
const std::string& value_str) const; const std::string& value_str) const;
void report_min_value_error(yajlpp_parse_context* ypc, void report_min_value_error(yajlpp_parse_context* ypc,
@ -350,7 +353,7 @@ public:
void reset(const struct json_path_container* handlers); void reset(const struct json_path_container* handlers);
void set_static_handler(struct json_path_handler_base& jph); void set_static_handler(const struct json_path_handler_base& jph);
template<typename T> template<typename T>
yajlpp_parse_context& with_obj(T& obj) yajlpp_parse_context& with_obj(T& obj)

View File

@ -41,33 +41,6 @@
#include "relative_time.hh" #include "relative_time.hh"
#include "yajlpp.hh" #include "yajlpp.hh"
#define FOR_FIELD(T, FIELD) for_field<T, decltype(T ::FIELD), &T ::FIELD>()
inline intern_string_t&
assign(intern_string_t& lhs, const string_fragment& rhs)
{
lhs = intern_string::lookup(rhs.data(), rhs.length());
return lhs;
}
inline std::string&
assign(std::string& lhs, const string_fragment& rhs)
{
lhs.assign(rhs.data(), rhs.length());
return lhs;
}
template<template<typename...> class Container>
inline Container<std::string>&
assign(Container<std::string>& lhs, const string_fragment& rhs)
{
lhs.emplace_back(rhs.data(), rhs.length());
return lhs;
}
struct json_null_t { struct json_null_t {
bool operator==(const json_null_t& other) const { return true; } bool operator==(const json_null_t& other) const { return true; }
}; };
@ -246,54 +219,6 @@ struct json_path_handler : public json_path_handler_base {
return *this; return *this;
} }
template<typename T, typename MEM_T, MEM_T T::*MEM>
static void* get_field_lvalue_cb(void* root,
nonstd::optional<std::string> name)
{
auto obj = (T*) root;
auto& mem = obj->*MEM;
return &mem;
}
template<typename T, typename STR_T, STR_T T::*STR>
static int string_field_cb(yajlpp_parse_context* ypc,
const unsigned char* str,
size_t len)
{
auto handler = ypc->ypc_current_handler;
if (ypc->ypc_locations) {
(*ypc->ypc_locations)[ypc->get_full_path()]
= source_location{ypc->ypc_source, ypc->get_line_number()};
}
assign(ypc->get_lvalue(ypc->get_obj_member<T, STR_T, STR>()),
string_fragment(str, 0, len));
handler->jph_validator(*ypc, *handler);
return 1;
}
template<typename T, typename ENUM_T, ENUM_T T::*ENUM>
static int enum_field_cb(yajlpp_parse_context* ypc,
const unsigned char* str,
size_t len)
{
auto obj = (T*) ypc->ypc_obj_stack.top();
auto handler = ypc->ypc_current_handler;
auto res = handler->to_enum_value(string_fragment(str, 0, len));
if (res) {
obj->*ENUM = (ENUM_T) res.value();
} else {
handler->report_enum_error(ypc,
std::string((const char*) str, len));
}
return 1;
}
static int null_field_cb(yajlpp_parse_context* ypc) static int null_field_cb(yajlpp_parse_context* ypc)
{ {
return ypc->ypc_current_handler->jph_null_cb(ypc); return ypc->ypc_current_handler->jph_null_cb(ypc);
@ -316,204 +241,9 @@ struct json_path_handler : public json_path_handler_base {
return ypc->ypc_current_handler->jph_integer_cb(ypc, val); return ypc->ypc_current_handler->jph_integer_cb(ypc, val);
} }
template<typename T, typename NUM_T, NUM_T T::*NUM> static int dbl_field_cb(yajlpp_parse_context* ypc, double val)
static int num_field_cb(yajlpp_parse_context* ypc, long long num)
{ {
auto obj = (T*) ypc->ypc_obj_stack.top(); return ypc->ypc_current_handler->jph_double_cb(ypc, val);
obj->*NUM = num;
return 1;
}
template<typename T, typename NUM_T, NUM_T T::*NUM>
static int decimal_field_cb(yajlpp_parse_context* ypc, double num)
{
auto obj = (T*) ypc->ypc_obj_stack.top();
obj->*NUM = num;
return 1;
}
template<typename T, typename STR_T, STR_T T::*STR>
static void string_field_validator(yajlpp_parse_context& ypc,
const json_path_handler_base& jph)
{
auto& field_ptr = ypc.get_rvalue(ypc.get_obj_member<T, STR_T, STR>());
if (jph.jph_pattern) {
auto sf = to_string_fragment(field_ptr);
if (!jph.jph_pattern->find_in(sf).ignore_error()) {
jph.report_pattern_error(&ypc, sf.to_string());
}
}
if (field_ptr.empty() && jph.jph_min_length > 0) {
ypc.report_error(
lnav::console::user_message::error(
attr_line_t("invalid value for option ")
.template append_quoted(lnav::roles::symbol(
ypc.get_full_path().to_string())))
.with_reason("empty values are not allowed")
.with_snippet(ypc.get_snippet())
.with_help(jph.get_help_text(&ypc)));
} else if (field_ptr.size() < jph.jph_min_length) {
ypc.report_error(
lnav::console::user_message::error(
attr_line_t()
.template append_quoted(field_ptr)
.append(" is not a valid value for option ")
.append_quoted(lnav::roles::symbol(
ypc.get_full_path().to_string())))
.with_reason(attr_line_t("value must be at least ")
.append(lnav::roles::number(
fmt::to_string(jph.jph_min_length)))
.append(" characters long"))
.with_snippet(ypc.get_snippet())
.with_help(jph.get_help_text(&ypc)));
}
}
template<typename T, typename NUM_T, NUM_T T::*NUM>
static void number_field_validator(yajlpp_parse_context& ypc,
const json_path_handler_base& jph)
{
auto& field_ptr = ypc.get_rvalue(ypc.get_obj_member<T, NUM_T, NUM>());
if (field_ptr < jph.jph_min_value) {
jph.report_min_value_error(&ypc, field_ptr);
}
}
template<typename T, typename R, R T::*FIELD>
static yajl_gen_status field_gen(yajlpp_gen_context& ygc,
const json_path_handler_base& jph,
yajl_gen handle)
{
auto def_obj = (T*) (ygc.ygc_default_stack.empty()
? nullptr
: ygc.ygc_default_stack.top());
auto obj = (T*) ygc.ygc_obj_stack.top();
if (def_obj != nullptr && def_obj->*FIELD == obj->*FIELD) {
return yajl_gen_status_ok;
}
if (ygc.ygc_depth) {
yajl_gen_string(handle, jph.jph_property);
}
yajlpp_generator gen(handle);
return gen(obj->*FIELD);
}
template<typename T, typename R, R T::*FIELD>
static yajl_gen_status map_field_gen(yajlpp_gen_context& ygc,
const json_path_handler_base& jph,
yajl_gen handle)
{
const auto def_container = (T*) (ygc.ygc_default_stack.empty()
? nullptr
: ygc.ygc_default_stack.top());
auto container = (T*) ygc.ygc_obj_stack.top();
auto& obj = container->*FIELD;
yajl_gen_status rc;
for (const auto& pair : obj) {
if (def_container != nullptr) {
auto& def_obj = def_container->*FIELD;
auto iter = def_obj.find(pair.first);
if (iter != def_obj.end() && iter->second == pair.second) {
continue;
}
}
if ((rc = yajl_gen_string(handle, pair.first))
!= yajl_gen_status_ok)
{
return rc;
}
if ((rc = yajl_gen_string(handle, pair.second))
!= yajl_gen_status_ok)
{
return rc;
}
}
return yajl_gen_status_ok;
}
template<typename T, typename STR_T, std::string T::*STR>
json_path_handler& for_field()
{
this->add_cb(string_field_cb<T, STR_T, STR>);
this->jph_gen_callback = field_gen<T, STR_T, STR>;
this->jph_validator = string_field_validator<T, STR_T, STR>;
this->jph_field_getter = get_field_lvalue_cb<T, STR_T, STR>;
return *this;
}
template<typename T,
typename STR_T,
std::map<std::string, std::string> T::*STR>
json_path_handler& for_field()
{
this->add_cb(string_field_cb<T, STR_T, STR>);
this->jph_gen_callback = map_field_gen<T, STR_T, STR>;
this->jph_validator = string_field_validator<T, STR_T, STR>;
return *this;
}
template<typename T,
typename STR_T,
std::map<std::string, std::vector<std::string>> T::*STR>
json_path_handler& for_field()
{
this->add_cb(string_field_cb<T, STR_T, STR>);
this->jph_validator = string_field_validator<T, STR_T, STR>;
return *this;
}
template<typename T, typename STR_T, std::vector<std::string> T::*STR>
json_path_handler& for_field()
{
this->add_cb(string_field_cb<T, STR_T, STR>);
this->jph_gen_callback = field_gen<T, STR_T, STR>;
this->jph_validator = string_field_validator<T, STR_T, STR>;
return *this;
}
template<typename T, typename STR_T, intern_string_t T::*STR>
json_path_handler& for_field()
{
this->add_cb(string_field_cb<T, intern_string_t, STR>);
this->jph_gen_callback = field_gen<T, intern_string_t, STR>;
this->jph_validator = string_field_validator<T, intern_string_t, STR>;
return *this;
}
template<typename T, typename BOOL_T, bool T::*BOOL>
json_path_handler& for_field()
{
this->add_cb(bool_field_cb);
this->jph_bool_cb = [&](yajlpp_parse_context* ypc, int val) {
auto obj = (T*) ypc->ypc_obj_stack.top();
obj->*BOOL = static_cast<bool>(val);
return 1;
};
this->jph_gen_callback = field_gen<T, bool, BOOL>;
return *this;
} }
template<typename T, typename U> template<typename T, typename U>
@ -572,22 +302,37 @@ struct json_path_handler : public json_path_handler_base {
}; };
template<typename T, typename... Args> template<typename T, typename... Args>
struct LastIsNumber { struct LastIsInteger {
static constexpr bool value = LastIsNumber<Args...>::value; static constexpr bool value = LastIsInteger<Args...>::value;
}; };
template<typename T, typename U> template<typename T, typename U>
struct LastIsNumber<U T::*> { struct LastIsInteger<U T::*> {
static constexpr bool value static constexpr bool value
= std::is_integral<U>::value && !std::is_same<U, bool>::value; = std::is_integral<U>::value && !std::is_same<U, bool>::value;
}; };
template<typename T, typename U> template<typename T, typename U>
struct LastIsNumber<nonstd::optional<U> T::*> { struct LastIsInteger<nonstd::optional<U> T::*> {
static constexpr bool value static constexpr bool value
= std::is_integral<U>::value && !std::is_same<U, bool>::value; = std::is_integral<U>::value && !std::is_same<U, bool>::value;
}; };
template<typename T, typename... Args>
struct LastIsFloat {
static constexpr bool value = LastIsFloat<Args...>::value;
};
template<typename T, typename U>
struct LastIsFloat<U T::*> {
static constexpr bool value = std::is_same<U, double>::value;
};
template<typename T, typename U>
struct LastIsFloat<nonstd::optional<U> T::*> {
static constexpr bool value = std::is_same<U, double>::value;
};
template<typename T, typename... Args> template<typename T, typename... Args>
struct LastIsVector { struct LastIsVector {
using value_type = typename LastIsVector<Args...>::value_type; using value_type = typename LastIsVector<Args...>::value_type;
@ -675,12 +420,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
json_path_handler::get_field(obj, args...) json_path_handler::get_field(obj, args...)
.emplace_back(std::move(value_str)); .emplace_back(std::move(value_str));
@ -937,12 +677,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
json_path_handler::get_field(obj, args...) = std::move(value_str); json_path_handler::get_field(obj, args...) = std::move(value_str);
return 1; return 1;
@ -1055,12 +790,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
json_path_handler::get_field(obj, args...) = std::move(value_str); json_path_handler::get_field(obj, args...) = std::move(value_str);
return 1; return 1;
@ -1114,12 +844,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
auto& field = json_path_handler::get_field(obj, args...); auto& field = json_path_handler::get_field(obj, args...);
field.pp_path = ypc->get_full_path(); field.pp_path = ypc->get_full_path();
@ -1168,12 +893,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
json_path_handler::get_field(obj, args...) json_path_handler::get_field(obj, args...)
= intern_string::lookup(value_str); = intern_string::lookup(value_str);
@ -1220,12 +940,7 @@ struct json_path_handler : public json_path_handler_base {
auto value_str = std::string((const char*) str, len); auto value_str = std::string((const char*) str, len);
auto jph = ypc->ypc_current_handler; auto jph = ypc->ypc_current_handler;
if (jph->jph_pattern) { jph->validate_string(*ypc, value_str);
if (!jph->jph_pattern->find_in(value_str).ignore_error()) {
jph->report_pattern_error(ypc, value_str);
}
}
auto& field = json_path_handler::get_field(obj, args...); auto& field = json_path_handler::get_field(obj, args...);
field.pp_path = ypc->get_full_path(); field.pp_path = ypc->get_full_path();
field.pp_location.sl_source = ypc->ypc_source; field.pp_location.sl_source = ypc->ypc_source;
@ -1297,7 +1012,7 @@ struct json_path_handler : public json_path_handler_base {
} }
template<typename... Args, template<typename... Args,
std::enable_if_t<LastIsNumber<Args...>::value, bool> = true> std::enable_if_t<LastIsInteger<Args...>::value, bool> = true>
json_path_handler& for_field(Args... args) json_path_handler& for_field(Args... args)
{ {
this->add_cb(int_field_cb); this->add_cb(int_field_cb);
@ -1350,6 +1065,59 @@ struct json_path_handler : public json_path_handler_base {
return *this; return *this;
} }
template<typename... Args,
std::enable_if_t<LastIsFloat<Args...>::value, bool> = true>
json_path_handler& for_field(Args... args)
{
this->add_cb(dbl_field_cb);
this->jph_double_cb = [args...](yajlpp_parse_context* ypc, double val) {
auto jph = ypc->ypc_current_handler;
auto* obj = ypc->ypc_obj_stack.top();
if (val < jph->jph_min_value) {
jph->report_min_value_error(ypc, val);
return 1;
}
json_path_handler::get_field(obj, args...) = val;
return 1;
};
this->jph_gen_callback = [args...](yajlpp_gen_context& ygc,
const json_path_handler_base& jph,
yajl_gen handle) {
const auto& field = json_path_handler::get_field(
ygc.ygc_obj_stack.top(), args...);
if (!ygc.ygc_default_stack.empty()) {
const auto& field_def = json_path_handler::get_field(
ygc.ygc_default_stack.top(), args...);
if (field == field_def) {
return yajl_gen_status_ok;
}
}
if (!is_field_set(field)) {
return yajl_gen_status_ok;
}
if (ygc.ygc_depth) {
yajl_gen_string(handle, jph.jph_property);
}
yajlpp_generator gen(handle);
return gen(field);
};
this->jph_field_getter
= [args...](void* root, nonstd::optional<std::string> name) {
return (void*) &json_path_handler::get_field(root, args...);
};
return *this;
}
template< template<
typename... Args, typename... Args,
std::enable_if_t<LastIs<std::chrono::seconds, Args...>::value, bool> std::enable_if_t<LastIs<std::chrono::seconds, Args...>::value, bool>
@ -1465,34 +1233,6 @@ struct json_path_handler : public json_path_handler_base {
}; };
return *this; return *this;
};
template<typename T, typename NUM_T, NUM_T T::*NUM>
json_path_handler& for_field(
typename std::enable_if<std::is_integral<NUM_T>::value
&& !std::is_same<NUM_T, bool>::value>::type*
dummy
= 0)
{
this->add_cb(num_field_cb<T, NUM_T, NUM>);
this->jph_validator = number_field_validator<T, NUM_T, NUM>;
return *this;
}
template<typename T, typename NUM_T, double T::*NUM>
json_path_handler& for_field()
{
this->add_cb(decimal_field_cb<T, NUM_T, NUM>);
this->jph_validator = number_field_validator<T, NUM_T, NUM>;
return *this;
}
template<typename T, typename ENUM_T, ENUM_T T::*ENUM>
json_path_handler& for_field(
typename std::enable_if<std::is_enum<ENUM_T>::value>::type* dummy = 0)
{
this->add_cb(enum_field_cb<T, ENUM_T, ENUM>);
return *this;
} }
json_path_handler& with_children(const json_path_container& container); json_path_handler& with_children(const json_path_container& container);
@ -1617,7 +1357,7 @@ struct typed_json_path_container : public json_path_container {
return gen.to_string_fragment().to_string(); return gen.to_string_fragment().to_string();
} }
json_string to_json_string(T& obj) const json_string to_json_string(const T& obj) const
{ {
yajlpp_gen gen; yajlpp_gen gen;
yajlpp_gen_context ygc(gen, *this); yajlpp_gen_context ygc(gen, *this);

View File

@ -226,6 +226,7 @@ dist_noinst_DATA = \
expected/test_tailer.sh_12f539e535df04364316699f9edeac461aa9f9de.err \ expected/test_tailer.sh_12f539e535df04364316699f9edeac461aa9f9de.err \
expected/test_tailer.sh_12f539e535df04364316699f9edeac461aa9f9de.out \ expected/test_tailer.sh_12f539e535df04364316699f9edeac461aa9f9de.out \
ansi-colors.0.in \ ansi-colors.0.in \
bad-config/formats/invalid-json-format/format.json \
bad-config/formats/invalid-properties/format.json \ bad-config/formats/invalid-properties/format.json \
bad-config/formats/invalid-regex/format.json \ bad-config/formats/invalid-regex/format.json \
bad-config/formats/invalid-sample/format.json \ bad-config/formats/invalid-sample/format.json \

View File

@ -0,0 +1,17 @@
{
"$schema": "https://lnav.org/schemas/format-v1.schema.json",
"bad_json_log": {
"json": true,
"line-format": [
{
"field": ""
},
{
"field": "__timestamp__",
"timestamp-format": ""
}
],
"value": {
}
}
}

View File

@ -1,3 +1,11 @@
✘ error: invalid value for option “/bad_json_log/line-format#/timestamp-format”
reason: empty values are not allowed
 --> {test_dir}/bad-config/formats/invalid-json-format/format.json:11
 |  "timestamp-format": "" 
 = help: Property Synopsis
/bad_json_log/line-format#/timestamp-format <string>
Description
The strftime(3) format for this field
✘ error: “invalid(abc” is not a valid regular expression ✘ error: “invalid(abc” is not a valid regular expression
reason: missing closing parenthesis reason: missing closing parenthesis
 --> /invalid_props_log/tags/badtag3/pattern  --> /invalid_props_log/tags/badtag3/pattern
@ -78,6 +86,9 @@
/$schema The URI of the schema for this file /$schema The URI of the schema for this file
Description Description
Specifies the type of this file Specifies the type of this file
✘ error: invalid line format element “/bad_json_log/line-format/0/field”
reason: “” is not a defined value
 --> {test_dir}/bad-config/formats/invalid-json-format/format.json:7
✘ error: invalid pattern: “incomplete-match” ✘ error: invalid pattern: “incomplete-match”
reason: pattern does not match entire message reason: pattern does not match entire message
 --> {test_dir}/bad-config/formats/invalid-regex/format.json:20  --> {test_dir}/bad-config/formats/invalid-regex/format.json:20