Exemplo n.º 1
0
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));
  }
}
Exemplo n.º 2
0
/* parse an expression term. It can be one of:
 * "term"
 * ["term" <parameters>]
 */
std::unique_ptr<QueryExpr> w_query_expr_parse(
    w_query* query,
    const json_ref& exp) {
  w_string name;

  if (exp.isString()) {
    name = json_to_w_string(exp);
  } else if (exp.isArray() && json_array_size(exp) > 0) {
    const auto& first = exp.at(0);

    if (!first.isString()) {
      throw QueryParseError("first element of an expression must be a string");
    }
    name = json_to_w_string(first);
  } else {
    throw QueryParseError("expected array or string for an expression");
  }

  auto it = term_hash().find(name);
  if (it == term_hash().end()) {
    throw QueryParseError(
        watchman::to<std::string>("unknown expression term '", name, "'"));
  }
  return it->second(query, exp);
}
Exemplo n.º 3
0
static void parse_lock_timeout(w_query* res, const json_ref& query) {
  int value = DEFAULT_QUERY_SYNC_MS.count();

  if (query &&
      json_unpack(query, "{s?:i*}", "lock_timeout", &value) != 0) {
    throw QueryParseError("lock_timeout must be an integer value >= 0");
  }

  if (value < 0) {
    throw QueryParseError("lock_timeout must be an integer value >= 0");
  }

  res->lock_timeout = value;
}
Exemplo n.º 4
0
static void parse_sync(w_query* res, const json_ref& query) {
  int value = DEFAULT_QUERY_SYNC_MS.count();

  if (query &&
      json_unpack(query, "{s?:i*}", "sync_timeout", &value) != 0) {
    throw QueryParseError("sync_timeout must be an integer value >= 0");
  }

  if (value < 0) {
    throw QueryParseError("sync_timeout must be an integer value >= 0");
  }

  res->sync_timeout = std::chrono::milliseconds(value);
}
Exemplo n.º 5
0
  static std::unique_ptr<QueryExpr> parse(w_query*, const json_ref& term) {
    const char *ignore, *typestr, *found;
    char arg;

    if (json_unpack(term, "[s,u]", &ignore, &typestr) != 0) {
      throw QueryParseError("must use [\"type\", \"typestr\"]");
    }

    found = strpbrk(typestr, "bcdfplsD");
    if (!found || strlen(typestr) > 1) {
      throw QueryParseError("invalid type string '", typestr, "'");
    }

    arg = *found;

    return watchman::make_unique<TypeExpr>(arg);
  }
Exemplo n.º 6
0
static w_string parse_suffix(const json_ref& ele) {
  if (!ele.isString()) {
    throw QueryParseError("'suffix' must be a string or an array of strings");
  }

  auto str = json_to_w_string(ele);

  return str.piece().asLowerCase(str.type());
}
Exemplo n.º 7
0
static void parse_empty_on_fresh_instance(w_query* res, const json_ref& query) {
  int value = 0;

  if (query &&
      json_unpack(query, "{s?:b*}", "empty_on_fresh_instance", &value) != 0) {
    throw QueryParseError("empty_on_fresh_instance must be a boolean");
  }

  res->empty_on_fresh_instance = (bool) value;
}
Exemplo n.º 8
0
static void parse_dedup(w_query* res, const json_ref& query) {
  int value = 0;

  if (query &&
      json_unpack(query, "{s?:b*}", "dedup_results", &value) != 0) {
    throw QueryParseError("dedup_results must be a boolean");
  }

  res->dedup_results = (bool) value;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
static void parse_case_sensitive(
    w_query* res,
    const std::shared_ptr<w_root_t>& root,
    const json_ref& query) {
  int value = root->case_sensitive == CaseSensitivity::CaseSensitive;

  if (query && json_unpack(query, "{s?:b*}", "case_sensitive", &value) != 0) {
    throw QueryParseError("case_sensitive must be a boolean");
  }

  res->case_sensitive = value ? CaseSensitivity::CaseSensitive
                              : CaseSensitivity::CaseInSensitive;
}
Exemplo n.º 12
0
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");
    }
  }
}
Exemplo n.º 13
0
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'");
}
Exemplo n.º 14
0
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());
}
Exemplo n.º 15
0
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");
  }
}
Exemplo n.º 16
0
// 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;
}