Skip to content

Commit

Permalink
Refactor resolve_root_or_err to throw exceptions
Browse files Browse the repository at this point in the history
Summary:
In the current form of resolve_root_or_err,  its behavior is:
1) returns a string error message
2) returns null on failure
3) notifies client connection of failure
All clients must handle the null return - which can lead to bugs.

We updated the implementation to be less error prone:
1) throw an exception on error - that contains the error message.
This frees clients from having to null check (command dispatch
will take care of catching the exception).

Note: we still have to pass in the client to the resolve_root method because
there are checks for client_is_owner and client_mode.

Reviewed By: wez

Differential Revision: D5826757

fbshipit-source-id: 579f55c64ca9daf3fa4ebd4a6ac4d7dab19a2d53
  • Loading branch information
eamonnkent authored and facebook-github-bot committed Sep 15, 2017
1 parent 2ba4052 commit 02934e4
Show file tree
Hide file tree
Showing 15 changed files with 58 additions and 112 deletions.
6 changes: 2 additions & 4 deletions InMemoryView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,10 +768,8 @@ void InMemoryView::debugContentHashCache(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto view = std::dynamic_pointer_cast<watchman::InMemoryView>(root->view());
if (!view) {
send_error_response(client, "root is not an InMemoryView watcher");
Expand Down
26 changes: 5 additions & 21 deletions cmds/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ static void cmd_debug_recrawl(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();

Expand All @@ -39,10 +36,7 @@ static void cmd_debug_show_cursors(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();

Expand Down Expand Up @@ -75,10 +69,7 @@ static void cmd_debug_ageout(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

std::chrono::seconds min_age(json_integer_value(json_array_get(args, 2)));

Expand All @@ -96,10 +87,7 @@ static void cmd_debug_poison(
const json_ref& args) {
struct timeval now;

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

gettimeofday(&now, NULL);

Expand Down Expand Up @@ -178,11 +166,7 @@ static void cmd_debug_get_subscriptions(
const json_ref& args) {
auto client = (watchman_user_client*)clientbase;

auto root = resolve_root_or_err(client, args, 1, false);

if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();
auto debug_info = root->unilateralResponses->getDebugInfo();
Expand Down
5 changes: 1 addition & 4 deletions cmds/find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ static void cmd_find(struct watchman_client* client, const json_ref& args) {
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto query = w_query_parse_legacy(root, args, 2, nullptr, nullptr, nullptr);
if (client->client_mode) {
Expand Down
5 changes: 1 addition & 4 deletions cmds/info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ static void cmd_get_config(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();

Expand Down
5 changes: 1 addition & 4 deletions cmds/query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ static void cmd_query(struct watchman_client* client, const json_ref& args) {
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

const auto& query_spec = args.at(2);
auto query = w_query_parse(root, query_spec);
Expand Down
5 changes: 1 addition & 4 deletions cmds/since.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ static void cmd_since(struct watchman_client* client, const json_ref& args) {
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto clock_ele = json_array_get(args, 2);
clockspec = json_string_value(clock_ele);
Expand Down
10 changes: 2 additions & 8 deletions cmds/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ static void cmd_state_enter(
json_ref response;
auto client = dynamic_cast<watchman_user_client*>(clientbase);

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);

if (!parse_state_arg(client, args, &parsed)) {
return;
Expand Down Expand Up @@ -198,10 +195,7 @@ static void cmd_state_leave(
auto client = dynamic_cast<watchman_user_client*>(clientbase);
json_ref response;

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);

if (!parse_state_arg(client, args, &parsed)) {
return;
Expand Down
15 changes: 3 additions & 12 deletions cmds/subscribe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,7 @@ static void cmd_flush_subscriptions(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

std::vector<w_string> subs_to_sync;
if (subs) {
Expand Down Expand Up @@ -398,10 +395,7 @@ static void cmd_unsubscribe(
struct watchman_user_client* client =
(struct watchman_user_client*)clientbase;

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto jstr = json_array_get(args, 2);
name = json_string_value(jstr);
Expand Down Expand Up @@ -448,10 +442,7 @@ static void cmd_subscribe(
return;
}

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);

jname = args.at(2);
if (!json_is_string(jname)) {
Expand Down
15 changes: 3 additions & 12 deletions cmds/trigger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ static void cmd_trigger_delete(
w_string tname;
bool res;

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

if (json_array_size(args) != 3) {
send_error_response(client, "wrong number of arguments");
Expand Down Expand Up @@ -126,10 +123,7 @@ W_CMD_REG("trigger-del", cmd_trigger_delete, CMD_DAEMON, w_cmd_realpath_root)
static void cmd_trigger_list(
struct watchman_client* client,
const json_ref& args) {
auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();
auto arr = root->triggerListToJson();
Expand Down Expand Up @@ -358,10 +352,7 @@ static void cmd_trigger(struct watchman_client* client, const json_ref& args) {
json_ref trig;
json_ref resp;

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);

if (json_array_size(args) < 3) {
send_error_response(client, "not enough arguments");
Expand Down
20 changes: 4 additions & 16 deletions cmds/watch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ static void cmd_clock(struct watchman_client* client, const json_ref& args) {
}

/* resolve the root */
auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

if (sync_timeout &&
!root->syncToNow(std::chrono::milliseconds(sync_timeout))) {
Expand Down Expand Up @@ -86,10 +83,7 @@ static void cmd_watch_delete(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto resp = make_response();
resp.set({{"watch-del", json_boolean(root->stopWatch())},
Expand Down Expand Up @@ -239,10 +233,7 @@ static void cmd_watch(struct watchman_client* client, const json_ref& args) {
return;
}

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);
root->view()->waitUntilReadyToQuery(root).wait();

auto resp = make_response();
Expand Down Expand Up @@ -281,10 +272,7 @@ static void cmd_watch_project(
return;
}

auto root = resolve_root_or_err(client, args, 1, true);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, true);

root->view()->waitUntilReadyToQuery(root).wait();

Expand Down
37 changes: 20 additions & 17 deletions listener-user.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#include "watchman_scopeguard.h"

// Functions relating to the per-user service

Expand Down Expand Up @@ -38,29 +39,30 @@ void add_root_warnings_to_response(
"`\n")));
}

std::shared_ptr<w_root_t> resolve_root_or_err(
std::shared_ptr<w_root_t> resolve_root(
struct watchman_client* client,
const json_ref& args,
size_t root_index,
bool create) {
const char *root_name;
char *errmsg = NULL;
char* errmsg = nullptr;

SCOPE_EXIT {
free(errmsg);
};

if (args.array().size() <= root_index) {
send_error_response(client, "wrong number of arguments");
return nullptr;
throw RootResolveError("wrong number of arguments");
}

const auto& ele = args.at(root_index);

root_name = json_string_value(ele);
if (!root_name) {
send_error_response(
client,
"invalid value for argument %" PRIsize_t
", expected a string naming the root dir",
root_index);
return nullptr;
throw RootResolveError(
"invalid value for argument ",
root_index,
", expected a string naming the root dir");
}

std::shared_ptr<w_root_t> root;
Expand All @@ -76,15 +78,16 @@ std::shared_ptr<w_root_t> resolve_root_or_err(

if (!root) {
if (!client->client_is_owner) {
send_error_response(client, "unable to resolve root %s: %s (this may be "
"because you are not the process owner)",
root_name, errmsg);
throw RootResolveError(
"unable to resolve root ",
root_name,
": ",
errmsg ? errmsg : "",
" (this may be because you are not the process owner)");
} else {
send_error_response(client, "unable to resolve root %s: %s", root_name,
errmsg);
throw RootResolveError(
"unable to resolve root ", root_name, ": ", errmsg ? errmsg : "");
}
free(errmsg);
return nullptr;
}

if (client->perf_sample) {
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/trigger-error.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function testBadArgs() {
$root = $dir->getPath();
$this->watch($root);

$this->assertTriggerRegError('wrong number of arguments', 'trigger');
$this->assertTriggerRegError('RootResolveError: wrong number of arguments', 'trigger');

$this->assertTriggerRegError(
'not enough arguments',
Expand Down
5 changes: 1 addition & 4 deletions watcher/fsevents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,10 +654,7 @@ static void cmd_debug_fsevents_inject_drop(
return;
}

auto root = resolve_root_or_err(client, args, 1, false);
if (!root) {
return;
}
auto root = resolve_root(client, args, 1, false);

auto watcher = watcherFromRoot(root);
if (!watcher) {
Expand Down
4 changes: 3 additions & 1 deletion watchman_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ bool enqueue_response(
json_ref&& json,
bool ping);

std::shared_ptr<w_root_t> resolve_root_or_err(
// Resolve the root. If the root cannot be resolved,
// a RootResolveError will be thrown
std::shared_ptr<w_root_t> resolve_root(
struct watchman_client* client,
const json_ref& args,
size_t root_index,
Expand Down
10 changes: 10 additions & 0 deletions watchman_query.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ class QueryExecError : public std::runtime_error {
std::forward<Args>(args)...)) {}
};

// represents an error resolving the root
class RootResolveError : public std::runtime_error {
public:
template <typename... Args>
explicit RootResolveError(Args&&... args)
: std::runtime_error(watchman::to<std::string>(
"RootResolveError: ",
std::forward<Args>(args)...)) {}
};

struct w_query {
watchman::CaseSensitivity case_sensitive{watchman::CaseSensitivity::CaseInSensitive};
bool empty_on_fresh_instance{false};
Expand Down

0 comments on commit 02934e4

Please sign in to comment.