From 1a86db6397faf5320551702589dc9eb3db913e2d Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 22 Jan 2014 16:57:43 -0500 Subject: [PATCH 1/3] Fix error message for watch-del --- cmds/watch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/watch.c b/cmds/watch.c index f74bafd30812..29e0037d5a8d 100644 --- a/cmds/watch.c +++ b/cmds/watch.c @@ -40,7 +40,7 @@ void cmd_watch_delete(struct watchman_client *client, json_t *args) /* resolve the root */ if (json_array_size(args) != 2) { - send_error_response(client, "wrong number of arguments to 'watch'"); + send_error_response(client, "wrong number of arguments to 'watch-del'"); return; } From 715b552c6310095fc1e8d863a0692078ac5097fb Mon Sep 17 00:00:00 2001 From: David Turner Date: Thu, 23 Jan 2014 11:29:25 -0500 Subject: [PATCH 2/3] Handle single suffixes as well as arrays --- README.markdown | 3 +- query/parse.c | 37 ++++++++++++--------- tests/integration/suffixgenerator.php | 46 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 tests/integration/suffixgenerator.php diff --git a/README.markdown b/README.markdown index 83fe42c4611c..d02ceab784dd 100644 --- a/README.markdown +++ b/README.markdown @@ -150,7 +150,8 @@ Watchman provides 4 generators: * **since**: generates a list of files that were modified since a specific clockspec. If this is not specified, this will be treated the same as if a clockspec from a different instance of watchman was passed in. - * **suffix**: generates a list of files that have a particular suffix + * **suffix**: generates a list of files that have a particular suffix or set + of suffixes. The value can be either a string or an array of strings. * **path**: generates a list of files based on their path and depth * **all**: generates a list of all known files diff --git a/query/parse.c b/query/parse.c index bf77e113d52d..57c83b31082e 100644 --- a/query/parse.c +++ b/query/parse.c @@ -82,6 +82,18 @@ static bool parse_since(w_query *res, json_t *query) return false; } +static bool set_suffix(w_query *res, json_t *ele, w_string_t **suffix) +{ + if (!json_is_string(ele)) { + res->errmsg = strdup("'suffix' must be a string or an array of strings"); + return false; + } + + *suffix = w_string_new_lower(json_string_value(ele)); + + return true; +} + static bool parse_suffixes(w_query *res, json_t *query) { json_t *suffixes; @@ -92,8 +104,15 @@ static bool parse_suffixes(w_query *res, json_t *query) return true; } + if (json_is_string(suffixes)) { + json_t *ele = suffixes; + res->nsuffixes = 1; + res->suffixes = calloc(res->nsuffixes, sizeof(w_string_t*)); + return set_suffix(res, ele, res->suffixes); + } + if (!json_is_array(suffixes)) { - res->errmsg = strdup("'suffix' must be an array of strings"); + res->errmsg = strdup("'suffix' must be a string or an array of strings"); return false; } @@ -106,27 +125,15 @@ static bool parse_suffixes(w_query *res, json_t *query) for (i = 0; i < json_array_size(suffixes); i++) { json_t *ele = json_array_get(suffixes, i); - char *low; - int j; if (!json_is_string(ele)) { - res->errmsg = strdup("'suffix' must be an array of strings"); + res->errmsg = strdup("'suffix' must be a string or an array of strings"); return false; } - low = strdup(json_string_value(ele)); - if (!low) { - res->errmsg = strdup("out of memory"); + if (!set_suffix(res, ele, res->suffixes + i)) { return false; } - - for (j = 0; low[j]; j++) { - low[j] = tolower(low[j]); - } - - res->suffixes[i] = w_string_new(low); - - free(low); } return true; diff --git a/tests/integration/suffixgenerator.php b/tests/integration/suffixgenerator.php new file mode 100644 index 000000000000..1830fe047e8c --- /dev/null +++ b/tests/integration/suffixgenerator.php @@ -0,0 +1,46 @@ +getPath()); + + touch("$root/foo.c"); + mkdir("$root/subdir"); + touch("$root/subdir/bar.txt"); + + $this->watch($root); + + $res = $this->watchmanCommand('query', $root, array( + 'expression' => array('true'), + 'fields' => array('name'), + 'suffix' => 'c' + )); + $this->assertEqual(array('foo.c'), $res['files']); + + $res = $this->watchmanCommand('query', $root, array( + 'expression' => array('true'), + 'fields' => array('name'), + 'suffix' => array('c','txt') + )); + sort($res['files']); + $this->assertEqual(array('foo.c', 'subdir/bar.txt'), $res['files']); + + + $res = $this->watchmanCommand('query', $root, array( + 'expression' => array('true'), + 'fields' => array('name'), + 'suffix' => array('a' => 'b') + )); + $this->assertEqual( + 'failed to parse query: \'suffix\' must be a string or an array of strings', + $res['error'] + ); + + } +} + +// vim:ts=2:sw=2:et: + From 097bb2a58b21f447f3c46bb2579453676c843a73 Mon Sep 17 00:00:00 2001 From: David Turner Date: Thu, 23 Jan 2014 11:29:48 -0500 Subject: [PATCH 3/3] Improve the documentation --- README.markdown | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index d02ceab784dd..78c59ed362db 100644 --- a/README.markdown +++ b/README.markdown @@ -149,10 +149,19 @@ Watchman provides 4 generators: * **since**: generates a list of files that were modified since a specific clockspec. If this is not specified, this will be treated the same as if a - clockspec from a different instance of watchman was passed in. + clockspec from a different instance of watchman was passed in. You can + use either a string oclock value, or a integer number of epoch seconds. * **suffix**: generates a list of files that have a particular suffix or set of suffixes. The value can be either a string or an array of strings. - * **path**: generates a list of files based on their path and depth + * **path**: generates a list of files based on their path and depth. Depth + controls how far watchman will search down the directory tree for files. + Depth = 0 means only files and directories which are contained in this + path. The value of path can be either an array, a string, or an object. + If it is a string, it is treated as a path, and depth is infinite. If + an object, the fields path (a string) and depth (an integer) must be + supplied. An array can contain either strings or objects, each with the + same meaning as single strings or objects. Paths are relative to + the root, so if watchman is watching /foo/, path "bar" refers to /foo/bar. * **all**: generates a list of all known files Generators are analogous to the list of *paths* that you specify when using the @@ -642,12 +651,13 @@ fields will return a response something like this: } ``` -The `is_fresh_instance` member is true if the particular clock value indicates -that it was returned by a different instance of watchman, or a named cursor -hasn't been seen before. In that case, only files that currently exist will be -returned, and all files will have `new` set to `true`. Advanced users may set -the input parameter `empty_on_fresh_instance` to true, in which case no files -will be returned for fresh instances. +For queries using the `since` generator, the `is_fresh_instance` member is true +if the particular clock value indicates that it was returned by a different +instance of watchman, or a named cursor hasn't been seen before. In that case, +only files that currently exist will be returned, and all files will have `new` +set to `true`. For all other queries, is_fresh_instance will always be true. +Advanced users may set the input parameter `empty_on_fresh_instance` to true, +in which case no files will be returned for fresh instances. If the `fields` member consists of a single entry, the files result will be a simple array of values; ```"fields": ["name"]``` produces: