static void parse_suffixes(w_query* res, const json_ref& query) { size_t i; auto suffixes = query.get_default("suffix"); if (!suffixes) { return; } if (suffixes.isString()) { auto suff = parse_suffix(suffixes); res->suffixes.emplace_back(std::move(suff)); return; } if (!suffixes.isArray()) { throw QueryParseError("'suffix' must be a string or an array of strings"); } res->suffixes.reserve(json_array_size(suffixes)); for (i = 0; i < json_array_size(suffixes); i++) { const auto& ele = suffixes.at(i); if (!ele.isString()) { throw QueryParseError("'suffix' must be a string or an array of strings"); } auto suff = parse_suffix(ele); res->suffixes.emplace_back(std::move(suff)); } }
static void parse_query_expression(w_query* res, const json_ref& query) { auto exp = query.get_default("expression"); if (!exp) { // Empty expression means that we emit all generated files return; } res->expr = w_query_expr_parse(res, exp); }
static void parse_benchmark(w_query* res, const json_ref& query) { // Preserve behavior by supporting a boolean value. Also support int values. auto bench = query.get_default("bench"); if (bench) { if (bench.isBool()) { res->bench_iterations = 100; } else { res->bench_iterations = json_integer_value(bench); } } }
static void parse_request_id(w_query* res, const json_ref& query) { auto request_id = query.get_default("request_id"); if (!request_id) { return; } if (!request_id.isString()) { throw QueryParseError("'request_id' must be a string"); } res->request_id = json_to_w_string(request_id); }
LocalSavedStateInterface::LocalSavedStateInterface( const json_ref& savedStateConfig, const SCM* scm) : SavedStateInterface(savedStateConfig), scm_(scm) { // Max commits to search in source control history for a saved state auto maxCommits = savedStateConfig.get_default("max-commits"); if (maxCommits) { if (!maxCommits.isInt()) { throw QueryParseError("'max-commits' must be an integer"); } maxCommits_ = json_integer_value(maxCommits); if (maxCommits_ < 1) { throw QueryParseError("'max-commits' must be a positive integer"); } } else { maxCommits_ = kDefaultMaxCommits; } // Local path to search for saved states. This path will only ever be read, // never written. auto localStoragePath = savedStateConfig.get_default("local-storage-path"); if (!localStoragePath) { throw QueryParseError( "'local-storage-path' must be present in saved state config"); } if (!localStoragePath.isString()) { throw QueryParseError("'local-storage-path' must be a string"); } localStoragePath_ = json_to_w_string(localStoragePath); if (!w_string_path_is_absolute(localStoragePath_)) { throw QueryParseError("'local-storage-path' must be an absolute path"); } // The saved state project must be a sub-directory in the local storage // path. if (w_string_path_is_absolute(project_)) { throw QueryParseError("'project' must be a relative path"); } }
static bool parse_since(w_query* res, const json_ref& query) { auto since = query.get_default("since"); if (!since) { return true; } auto spec = ClockSpec::parseOptionalClockSpec(since); if (spec) { // res owns the ref to spec res->since_spec = std::move(spec); return true; } throw QueryParseError("invalid value for 'since'"); }
static void parse_relative_root( const std::shared_ptr<w_root_t>& root, w_query* res, const json_ref& query) { auto relative_root = query.get_default("relative_root"); if (!relative_root) { return; } if (!relative_root.isString()) { throw QueryParseError("'relative_root' must be a string"); } auto path = json_to_w_string(relative_root).normalizeSeparators(); auto canon_path = w_string_canon_path(path); res->relative_root = w_string::pathCat({root->root_path, canon_path}); res->relative_root_slash = w_string::printf("%s/", res->relative_root.c_str()); }
static bool parse_paths(w_query* res, const json_ref& query) { size_t i; auto paths = query.get_default("path"); if (!paths) { return true; } if (!paths.isArray()) { throw QueryParseError("'path' must be an array"); } res->paths.resize(json_array_size(paths)); for (i = 0; i < json_array_size(paths); i++) { const auto& ele = paths.at(i); w_string name; res->paths[i].depth = -1; if (ele.isString()) { name = json_to_w_string(ele); } else if (ele.isObject()) { name = json_to_w_string(ele.get("path")); auto depth = ele.get("depth"); if (!depth.isInt()) { throw QueryParseError("path.depth must be an integer"); } res->paths[i].depth = json_integer_value(depth); } else { throw QueryParseError( "expected object with 'path' and 'depth' properties"); } res->paths[i].name = name.normalizeSeparators(); } return true; }
void parse_globs(w_query* res, const json_ref& query) { size_t i; int noescape = 0; int includedotfiles = 0; auto globs = query.get_default("glob"); if (!globs) { return; } if (!json_is_array(globs)) { throw QueryParseError("'glob' must be an array"); } // Globs implicitly enable dedup_results mode res->dedup_results = true; if (json_unpack(query, "{s?b}", "glob_noescape", &noescape) != 0) { throw QueryParseError("glob_noescape must be a boolean"); } if (json_unpack(query, "{s?b}", "glob_includedotfiles", &includedotfiles) != 0) { throw QueryParseError("glob_includedotfiles must be a boolean"); } res->glob_flags = (includedotfiles ? 0 : WM_PERIOD) | (noescape ? WM_NOESCAPE : 0); res->glob_tree = watchman::make_unique<watchman_glob_tree>("", 0); for (i = 0; i < json_array_size(globs); i++) { const auto& ele = globs.at(i); const auto& pattern = json_to_w_string(ele); if (!add_glob(res->glob_tree.get(), pattern)) { throw QueryParseError("failed to compile multi-glob"); } } }
std::shared_ptr<w_query> w_query_parse( const std::shared_ptr<w_root_t>& root, const json_ref& query) { auto result = std::make_shared<w_query>(); auto res = result.get(); parse_benchmark(res, query); parse_case_sensitive(res, root, query); parse_sync(res, query); parse_dedup(res, query); parse_lock_timeout(res, query); parse_relative_root(root, res, query); parse_empty_on_fresh_instance(res, query); /* Look for path generators */ parse_paths(res, query); /* Look for glob generators */ parse_globs(res, query); /* Look for suffix generators */ parse_suffixes(res, query); /* Look for since generator */ parse_since(res, query); parse_query_expression(res, query); parse_request_id(res, query); parse_field_list(query.get_default("fields"), &res->fieldList); res->query_spec = query; return result; }