/* 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); }
static json_t *build_subscription_results( struct watchman_client_subscription *sub, w_root_t *root) { w_query_res res; json_t *response; json_t *file_list; char clockbuf[128]; w_log(W_LOG_DBG, "running subscription rules! since %" PRIu32 "\n", sub->since.ticks); // Subscriptions never need to sync explicitly; we are only dispatched // at settle points which are by definition sync'd to the present time sub->query->sync_timeout = 0; if (!w_query_execute(sub->query, root, &res, subscription_generator, sub)) { w_log(W_LOG_ERR, "error running subscription query: %s", res.errmsg); w_query_result_free(&res); return NULL; } w_log(W_LOG_DBG, "subscription generated %" PRIu32 " results\n", res.num_results); file_list = w_query_results_to_json(&sub->field_list, res.num_results, res.results); w_query_result_free(&res); if (res.num_results == 0) { return NULL; } response = make_response(); if (clock_id_string(sub->since.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "since", json_string_nocheck(clockbuf)); } if (clock_id_string(res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } sub->since.is_timestamp = false; sub->since.ticks = res.ticks; set_prop(response, "files", file_list); set_prop(response, "root", json_string(root->root_path->buf)); set_prop(response, "subscription", json_string(sub->name->buf)); return response; }
void w_assess_trigger(w_root_t *root, struct watchman_trigger_command *cmd) { w_query_res res; struct w_clockspec *since_spec = cmd->query->since_spec; if (since_spec && since_spec->tag == w_cs_clock) { w_log(W_LOG_DBG, "running trigger rules! since %" PRIu32 "\n", since_spec->clock.ticks); } else { w_log(W_LOG_DBG, "running trigger rules!\n"); } // Triggers never need to sync explicitly; we are only dispatched // at settle points which are by definition sync'd to the present time cmd->query->sync_timeout = 0; if (!w_query_execute(cmd->query, root, &res, trigger_generator, cmd)) { w_log(W_LOG_ERR, "error running trigger query: %s", res.errmsg); w_query_result_free(&res); return; } w_log(W_LOG_DBG, "trigger generated %" PRIu32 " results\n", res.num_results); // create a new spec that will be used the next time cmd->query->since_spec = w_clockspec_new_clock(res.root_number, res.ticks); if (res.num_results) { spawn_command(root, cmd, &res, since_spec); } if (since_spec) { w_clockspec_free(since_spec); since_spec = NULL; } w_query_result_free(&res); }
static json_t *build_subscription_results( struct watchman_client_subscription *sub, w_root_t *root) { w_query_res res; json_t *response; json_t *file_list; char clockbuf[128]; struct w_clockspec *since_spec = sub->query->since_spec; if (since_spec && since_spec->tag == w_cs_clock) { w_log(W_LOG_DBG, "running subscription rules! since %" PRIu32 "\n", since_spec->clock.ticks); } else { w_log(W_LOG_DBG, "running subscription rules!\n"); } // Subscriptions never need to sync explicitly; we are only dispatched // at settle points which are by definition sync'd to the present time sub->query->sync_timeout = 0; if (!w_query_execute(sub->query, root, &res, subscription_generator, sub)) { w_log(W_LOG_ERR, "error running subscription query: %s", res.errmsg); w_query_result_free(&res); return NULL; } w_log(W_LOG_DBG, "subscription generated %" PRIu32 " results\n", res.num_results); if (res.num_results == 0) { w_query_result_free(&res); return NULL; } file_list = w_query_results_to_json(&sub->field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); // It is way too much of a hassle to try to recreate the clock value if it's // not a relative clock spec, and it's only going to happen on the first run // anyway, so just skip doing that entirely. if (since_spec && since_spec->tag == w_cs_clock && clock_id_string(since_spec->clock.root_number, since_spec->clock.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "since", json_string_nocheck(clockbuf)); } if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } // create a new spec that will be used the next time if (since_spec) { w_clockspec_free(since_spec); since_spec = NULL; } sub->query->since_spec = w_clockspec_new_clock(res.root_number, res.ticks); set_prop(response, "is_fresh_instance", json_boolean(res.is_fresh_instance)); set_prop(response, "files", file_list); set_prop(response, "root", json_string(root->root_path->buf)); set_prop(response, "subscription", json_string(sub->name->buf)); return response; }
/* query /root {query} */ static void cmd_query(struct watchman_client *client, json_t *args) { w_root_t *root; w_query *query; json_t *query_spec; char *errmsg = NULL; w_query_res res; json_t *response; json_t *file_list, *jfield_list; char clockbuf[128]; struct w_query_field_list field_list; if (json_array_size(args) != 3) { send_error_response(client, "wrong number of arguments for 'query'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } query_spec = json_array_get(args, 2); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); w_root_delref(root); return; } query = w_query_parse(root, query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); w_root_delref(root); return; } 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, "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); }
/* 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); }
static json_t *build_subscription_results( struct watchman_client_subscription *sub, w_root_t *root) { w_query_res res; json_t *response; json_t *file_list; char clockbuf[128]; struct w_clockspec *since_spec = sub->query->since_spec; if (since_spec && since_spec->tag == w_cs_clock) { w_log(W_LOG_DBG, "running subscription %s rules since %" PRIu32 "\n", sub->name->buf, since_spec->clock.ticks); } else { w_log(W_LOG_DBG, "running subscription %s rules (no since)\n", sub->name->buf); } // Subscriptions never need to sync explicitly; we are only dispatched // at settle points which are by definition sync'd to the present time sub->query->sync_timeout = 0; // We're called by the io thread, so there's little chance that the root // could be legitimately blocked by something else. That means that we // can use a short lock_timeout sub->query->lock_timeout = (uint32_t)cfg_get_int(root, "subscription_lock_timeout_ms", 100); if (!w_query_execute(sub->query, root, &res, subscription_generator, sub)) { w_log(W_LOG_ERR, "error running subscription %s query: %s", sub->name->buf, res.errmsg); w_query_result_free(&res); return NULL; } w_log(W_LOG_DBG, "subscription %s generated %" PRIu32 " results\n", sub->name->buf, res.num_results); if (res.num_results == 0) { update_subscription_ticks(sub, &res); w_query_result_free(&res); return NULL; } file_list = w_query_results_to_json(&sub->field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); // It is way too much of a hassle to try to recreate the clock value if it's // not a relative clock spec, and it's only going to happen on the first run // anyway, so just skip doing that entirely. if (since_spec && since_spec->tag == w_cs_clock && clock_id_string(since_spec->clock.root_number, since_spec->clock.ticks, clockbuf, sizeof(clockbuf))) { set_unicode_prop(response, "since", clockbuf); } if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_unicode_prop(response, "clock", clockbuf); } update_subscription_ticks(sub, &res); set_prop(response, "is_fresh_instance", json_boolean(res.is_fresh_instance)); set_prop(response, "files", file_list); set_prop(response, "root", w_string_to_json(root->root_path)); set_prop(response, "subscription", w_string_to_json(sub->name)); set_prop(response, "unilateral", json_true()); return response; }