/* find /root [patterns] */ static void cmd_find(struct watchman_client *client, json_t *args) { w_root_t *root; w_query *query; char *errmsg = NULL; struct w_query_field_list field_list; w_query_res res; json_t *response; json_t *file_list; char clockbuf[128]; /* resolve the root */ if (json_array_size(args) < 2) { send_error_response(client, "not enough arguments for 'find'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } query = w_query_parse_legacy(root, args, &errmsg, 2, NULL, NULL, NULL); if (errmsg) { send_error_response(client, "%s", errmsg); free(errmsg); w_root_delref(root); return; } w_query_legacy_field_list(&field_list); if (client->client_mode) { query->sync_timeout = 0; } if (!w_query_execute(query, root, &res, NULL, NULL)) { send_error_response(client, "query failed: %s", res.errmsg); w_query_result_free(&res); w_root_delref(root); w_query_delref(query); return; } w_query_delref(query); file_list = w_query_results_to_json(&field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } set_prop(response, "files", file_list); send_and_dispose_response(client, response); w_root_delref(root); }
// Translate from the legacy array into the new style, then // delegate to the main parser. // We build a big anyof expression std::shared_ptr<w_query> w_query_parse_legacy( const std::shared_ptr<w_root_t>& root, const json_ref& args, int start, uint32_t* next_arg, const char* clockspec, json_ref* expr_p) { bool include = true; bool negated = false; uint32_t i; const char *term_name = "match"; json_ref included, excluded; auto query_obj = json_object(); if (!args.isArray()) { throw QueryParseError("Expected an array"); } for (i = start; i < json_array_size(args); i++) { const char *arg = json_string_value(json_array_get(args, i)); if (!arg) { /* not a string value! */ throw QueryParseError(watchman::to<std::string>( "rule @ position ", i, " is not a string value")); } } for (i = start; i < json_array_size(args); i++) { const char *arg = json_string_value(json_array_get(args, i)); if (!strcmp(arg, "--")) { i++; break; } if (!strcmp(arg, "-X")) { include = false; continue; } if (!strcmp(arg, "-I")) { include = true; continue; } if (!strcmp(arg, "!")) { negated = true; continue; } if (!strcmp(arg, "-P")) { term_name = "ipcre"; continue; } if (!strcmp(arg, "-p")) { term_name = "pcre"; continue; } // Which group are we going to file it into json_ref container; if (include) { if (!included) { included = json_array({typed_string_to_json("anyof", W_STRING_UNICODE)}); } container = included; } else { if (!excluded) { excluded = json_array({typed_string_to_json("anyof", W_STRING_UNICODE)}); } container = excluded; } auto term = json_array({typed_string_to_json(term_name, W_STRING_UNICODE), typed_string_to_json(arg), typed_string_to_json("wholename", W_STRING_UNICODE)}); if (negated) { term = json_array({typed_string_to_json("not", W_STRING_UNICODE), term}); } json_array_append_new(container, std::move(term)); // Reset negated flag negated = false; term_name = "match"; } if (excluded) { excluded = json_array({typed_string_to_json("not", W_STRING_UNICODE), excluded}); } json_ref query_array; if (included && excluded) { query_array = json_array( {typed_string_to_json("allof", W_STRING_UNICODE), excluded, included}); } else if (included) { query_array = included; } else { query_array = excluded; } // query_array may be NULL, which means find me all files. // Otherwise, it is the expression we want to use. if (query_array) { json_object_set_new_nocheck( query_obj, "expression", std::move(query_array)); } // For trigger if (next_arg) { *next_arg = i; } if (clockspec) { json_object_set_new_nocheck(query_obj, "since", typed_string_to_json(clockspec, W_STRING_UNICODE)); } /* compose the query with the field list */ auto query = w_query_parse(root, query_obj); if (expr_p) { *expr_p = query_obj; } if (query) { w_query_legacy_field_list(&query->fieldList); } return query; }
/* since /root <timestamp> [patterns] */ static void cmd_since(struct watchman_client *client, json_t *args) { const char *clockspec; w_root_t *root; w_query *query; char *errmsg = NULL; struct w_query_field_list field_list; w_query_res res; json_t *response, *clock_ele; json_t *file_list; char clockbuf[128]; /* resolve the root */ if (json_array_size(args) < 3) { send_error_response(client, "not enough arguments for 'since'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } clock_ele = json_array_get(args, 2); clockspec = json_string_value(clock_ele); if (!clockspec) { send_error_response(client, "expected argument 2 to be a valid clockspec"); w_root_delref(root); return; } query = w_query_parse_legacy(args, &errmsg, 3, NULL, clockspec, NULL); if (errmsg) { send_error_response(client, "%s", errmsg); free(errmsg); w_root_delref(root); return; } w_query_legacy_field_list(&field_list); if (!w_query_execute(query, root, &res, NULL, NULL)) { send_error_response(client, "query failed: %s", res.errmsg); w_query_result_free(&res); w_root_delref(root); w_query_delref(query); return; } w_query_delref(query); file_list = w_query_results_to_json(&field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } set_prop(response, "is_fresh_instance", json_pack("b", res.is_fresh_instance)); set_prop(response, "files", file_list); send_and_dispose_response(client, response); w_root_delref(root); }