Пример #1
0
struct watchman_trigger_command *w_build_trigger_from_def(
  w_root_t *root, json_t *trig, char **errmsg)
{
  struct watchman_trigger_command *cmd;
  json_t *ele, *query;
  json_int_t jint;
  const char *name = NULL;

  cmd = calloc(1, sizeof(*cmd));
  if (!cmd) {
    *errmsg = strdup("no memory");
    return NULL;
  }

  cmd->definition = trig;
  json_incref(cmd->definition);

  query = json_pack("{s:O}", "expression",
      json_object_get(cmd->definition, "expression"));
  cmd->query = w_query_parse(query, errmsg);
  json_decref(query);

  if (!cmd->query) {
    w_trigger_command_free(cmd);
    return NULL;
  }

  json_unpack(trig, "{s:s}", "name", &name);
  if (!name) {
    *errmsg = strdup("invalid or missing name");
    w_trigger_command_free(cmd);
    return NULL;
  }

  cmd->triggername = w_string_new(name);
  cmd->command = json_object_get(trig, "command");
  if (cmd->command) {
    json_incref(cmd->command);
  }
  if (!cmd->command || !json_is_array(cmd->command) ||
      !json_array_size(cmd->command)) {
    *errmsg = strdup("invalid command array");
    w_trigger_command_free(cmd);
    return NULL;
  }

  json_unpack(trig, "{s:b}", "append_files", &cmd->append_files);

  ele = json_object_get(trig, "stdin");
  if (!ele) {
    cmd->stdin_style = input_dev_null;
  } else if (json_is_array(ele)) {
    cmd->stdin_style = input_json;
    if (!parse_field_list(ele, &cmd->field_list, errmsg)) {
      w_trigger_command_free(cmd);
      return NULL;
    }
  } else if (json_is_string(ele)) {
    const char *str = json_string_value(ele);
    if (!strcmp(str, "/dev/null")) {
      cmd->stdin_style = input_dev_null;
    } else if (!strcmp(str, "NAME_PER_LINE")) {
      cmd->stdin_style = input_name_list;
    } else {
      ignore_result(asprintf(errmsg, "invalid stdin value %s", str));
      w_trigger_command_free(cmd);
      return NULL;
    }
  } else {
    *errmsg = strdup("invalid value for stdin");
    w_trigger_command_free(cmd);
    return NULL;
  }

  jint = 0; // unlimited unless specified
  json_unpack(trig, "{s:I}", "max_files_stdin", &jint);
  if (jint < 0) {
    *errmsg = strdup("max_files_stdin must be >= 0");
    w_trigger_command_free(cmd);
    return NULL;
  }
  cmd->max_files_stdin = jint;

  json_unpack(trig, "{s:s}", "stdout", &cmd->stdout_name);
  json_unpack(trig, "{s:s}", "stderr", &cmd->stderr_name);

  if (!parse_redirection(&cmd->stdout_name, &cmd->stdout_flags,
        "stdout", errmsg)) {
    w_trigger_command_free(cmd);
    return NULL;
  }

  if (!parse_redirection(&cmd->stderr_name, &cmd->stderr_flags,
        "stderr", errmsg)) {
    w_trigger_command_free(cmd);
    return NULL;
  }

  // Copy current environment
  cmd->envht = w_envp_make_ht();

  // Set some standard vars
  w_envp_set(cmd->envht, "WATCHMAN_ROOT", root->root_path);
  w_envp_set_cstring(cmd->envht, "WATCHMAN_SOCK", get_sock_name());
  w_envp_set(cmd->envht, "WATCHMAN_TRIGGER", cmd->triggername);

  return cmd;
}
Пример #2
0
/* trigger /root triggername [watch patterns] -- cmd to run
 * Sets up a trigger so that we can execute a command when a change
 * is detected */
static void cmd_trigger(struct watchman_client *client, json_t *args)
{
  w_root_t *root;
  struct watchman_trigger_command *cmd, *old;
  json_t *resp;
  json_t *trig;
  char *errmsg = NULL;
  bool need_save = true;

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

  if (json_array_size(args) < 3) {
    send_error_response(client, "not enough arguments");
    goto done;
  }

  trig = json_array_get(args, 2);
  if (json_is_string(trig)) {
    trig = build_legacy_trigger(root, client, args);
    if (!trig) {
      goto done;
    }
  } else {
    // Add a ref so that we don't need to conditionally decref later
    // for the legacy case later
    json_incref(trig);
  }

  cmd = w_build_trigger_from_def(root, trig, &errmsg);
  json_decref(trig);

  if (!cmd) {
    send_error_response(client, "%s", errmsg);
    goto done;
  }

  resp = make_response();
  set_prop(resp, "triggerid", json_string_nocheck(cmd->triggername->buf));

  w_root_lock(root);

  old = w_ht_val_ptr(w_ht_get(root->commands,
          w_ht_ptr_val(cmd->triggername)));
  if (old && json_equal(cmd->definition, old->definition)) {
    // Same definition: we don't and shouldn't touch things, so that we
    // preserve the associated trigger clock and don't cause the trigger
    // to re-run immediately
    set_prop(resp, "disposition", json_string_nocheck("already_defined"));
    w_trigger_command_free(cmd);
    cmd = NULL;
    need_save = false;
  } else {
    set_prop(resp, "disposition", json_string_nocheck(
          old ? "replaced" : "created"));
    w_ht_replace(root->commands, w_ht_ptr_val(cmd->triggername),
        w_ht_ptr_val(cmd));
    // Force the trigger to be eligible to run now
    root->ticks++;
    root->pending_trigger_tick = root->ticks;
  }
  w_root_unlock(root);

  if (need_save) {
    w_state_save();
  }

  send_and_dispose_response(client, resp);

done:
  if (errmsg) {
    free(errmsg);
  }
  w_root_delref(root);
}