Re: [Patch v2 2/9] notmuch-tag.c: convert to use tag-utils
authorJani Nikula <jani@nikula.org>
Mon, 7 Jan 2013 18:52:02 +0000 (20:52 +0200)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:53:01 +0000 (09:53 -0800)
1f/bcaa43a293174579030c8618bb76b785f16c51 [new file with mode: 0644]

diff --git a/1f/bcaa43a293174579030c8618bb76b785f16c51 b/1f/bcaa43a293174579030c8618bb76b785f16c51
new file mode 100644 (file)
index 0000000..6fea1aa
--- /dev/null
@@ -0,0 +1,388 @@
+Return-Path: <jani@nikula.org>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id 7BA17431FAF\r
+       for <notmuch@notmuchmail.org>; Mon,  7 Jan 2013 10:52:19 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.7\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
+       tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id vLDuLkK6BanN for <notmuch@notmuchmail.org>;\r
+       Mon,  7 Jan 2013 10:52:15 -0800 (PST)\r
+Received: from mail-la0-f46.google.com (mail-la0-f46.google.com\r
+       [209.85.215.46]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+       (No client certificate requested)\r
+       by olra.theworths.org (Postfix) with ESMTPS id 40024431FAE\r
+       for <notmuch@notmuchmail.org>; Mon,  7 Jan 2013 10:52:15 -0800 (PST)\r
+Received: by mail-la0-f46.google.com with SMTP id fq13so16849149lab.19\r
+       for <notmuch@notmuchmail.org>; Mon, 07 Jan 2013 10:52:13 -0800 (PST)\r
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+       d=google.com; s=20120113;\r
+       h=x-received:from:to:cc:subject:in-reply-to:references:user-agent\r
+       :date:message-id:mime-version:content-type:x-gm-message-state;\r
+       bh=nif7xF3g8c7npyjQq6hF9GlhdSnoOj5Mk04ABq56vI0=;\r
+       b=bqwieIp9a/i7gfX6ETevz4vgi2l048GEHGiZI73roF+B0eRKBTOhlBGEKoaw0yOpFs\r
+       1whT2B4J8iwXSgwoyDGHsOJUtZp63fheMHMpCi5tFSe/XkKuAA/0WxV5m0FeML1ssEGy\r
+       EL44CqSxxJtzQZ4bb7vInH7j5ujuB14MpTARqdR3u6Hk5K/doLK2YPVtjWXgzDihGghC\r
+       xUpCawa+0oMJXGCHQX9E3IN3m/OMfF19FniVm1czf8DQETvH0BDS0jYyYV5++2+K10vU\r
+       KSb2SXE1PZpKUhIosG0AgZGHfz+90xDuW9dQW1mY9oAqR9RVRzHtCPKWUKSYFz4Gqw/d\r
+       shFQ==\r
+X-Received: by 10.112.98.71 with SMTP id eg7mr25409594lbb.133.1357584732362;\r
+       Mon, 07 Jan 2013 10:52:12 -0800 (PST)\r
+Received: from localhost (dsl-hkibrasgw4-50df51-27.dhcp.inet.fi.\r
+       [80.223.81.27]) by mx.google.com with ESMTPS id\r
+       hc20sm23570663lab.11.2013.01.07.10.52.09\r
+       (version=SSLv3 cipher=OTHER); Mon, 07 Jan 2013 10:52:11 -0800 (PST)\r
+From: Jani Nikula <jani@nikula.org>\r
+To: david@tethera.net, notmuch@notmuchmail.org\r
+Subject: Re: [Patch v2 2/9] notmuch-tag.c: convert to use tag-utils\r
+In-Reply-To: <1357528614-6413-3-git-send-email-david@tethera.net>\r
+References: <1357528614-6413-1-git-send-email-david@tethera.net>\r
+       <1357528614-6413-3-git-send-email-david@tethera.net>\r
+User-Agent: Notmuch/0.14+211~gc8d6546 (http://notmuchmail.org) Emacs/24.2.1\r
+       (x86_64-pc-linux-gnu)\r
+Date: Mon, 07 Jan 2013 20:52:02 +0200\r
+Message-ID: <87obh0esh9.fsf@nikula.org>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain\r
+X-Gm-Message-State:\r
+ ALoCoQk3jsG1G3PwgTRGXNP9oqBwH6t6PCG7j84Jj8hMYdQ/rKU0xyQ68ATK8RAb9WzcfurR9pbZ\r
+Cc: David Bremner <bremner@debian.org>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Mon, 07 Jan 2013 18:52:19 -0000\r
+\r
+On Mon, 07 Jan 2013, david@tethera.net wrote:\r
+> From: David Bremner <bremner@debian.org>\r
+>\r
+> Command line parsing is factored out into a function\r
+> parse_tag_command_line in tag-utils.c.\r
+>\r
+> There is some duplicated code eliminated in tag_query, and a bunch of\r
+> translation from using the bare tag_op structs to using that tag-utils\r
+> API.\r
+> ---\r
+>  notmuch-tag.c |   99 ++++++++++++---------------------------------------------\r
+>  tag-util.c    |   51 +++++++++++++++++++++++++++--\r
+>  tag-util.h    |   15 +++++++++\r
+>  3 files changed, 84 insertions(+), 81 deletions(-)\r
+>\r
+> diff --git a/notmuch-tag.c b/notmuch-tag.c\r
+> index fc9d43a..8129912 100644\r
+> --- a/notmuch-tag.c\r
+> +++ b/notmuch-tag.c\r
+> @@ -19,6 +19,7 @@\r
+>   */\r
+>  \r
+>  #include "notmuch-client.h"\r
+> +#include "tag-util.h"\r
+>  #include "string-util.h"\r
+>  \r
+>  static volatile sig_atomic_t interrupted;\r
+> @@ -36,14 +37,10 @@ handle_sigint (unused (int sig))\r
+>      interrupted = 1;\r
+>  }\r
+>  \r
+> -typedef struct {\r
+> -    const char *tag;\r
+> -    notmuch_bool_t remove;\r
+> -} tag_operation_t;\r
+>  \r
+>  static char *\r
+>  _optimize_tag_query (void *ctx, const char *orig_query_string,\r
+> -                 const tag_operation_t *tag_ops)\r
+> +                 const tag_op_list_t *list)\r
+>  {\r
+>      /* This is subtler than it looks.  Xapian ignores the '-' operator\r
+>       * at the beginning both queries and parenthesized groups and,\r
+> @@ -60,7 +57,7 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
+>      size_t i;\r
+>  \r
+>      /* Don't optimize if there are no tag changes. */\r
+> -    if (tag_ops[0].tag == NULL)\r
+> +    if (tag_op_list_size (list) == 0)\r
+>      return talloc_strdup (ctx, orig_query_string);\r
+>  \r
+>      /* Build the new query string */\r
+> @@ -69,17 +66,17 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
+>      else\r
+>      query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);\r
+>  \r
+> -    for (i = 0; tag_ops[i].tag && query_string; i++) {\r
+> +    for (i = 0; i < tag_op_list_size (list) && query_string; i++) {\r
+>      /* XXX in case of OOM, query_string will be deallocated when\r
+>       * ctx is, which might be at shutdown */\r
+>      if (make_boolean_term (ctx,\r
+> -                           "tag", tag_ops[i].tag,\r
+> +                           "tag", tag_op_list_tag (list, i),\r
+>                             &escaped, &escaped_len))\r
+>          return NULL;\r
+>  \r
+>      query_string = talloc_asprintf_append_buffer (\r
+>          query_string, "%s%s%s", join,\r
+> -        tag_ops[i].remove ? "" : "not ",\r
+> +        tag_op_list_isremove (list, i) ? "" : "not ",\r
+>          escaped);\r
+>      join = " or ";\r
+>      }\r
+> @@ -91,17 +88,15 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,\r
+>      return query_string;\r
+>  }\r
+>  \r
+> -/* Tag messages matching 'query_string' according to 'tag_ops', which\r
+> - * must be an array of tagging operations terminated with an empty\r
+> - * element. */\r
+> +/* Tag messages matching 'query_string' according to 'tag_ops'\r
+> + */\r
+>  static int\r
+>  tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
+> -       tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags)\r
+> +       tag_op_list_t *tag_ops, tag_op_flag_t flags)\r
+>  {\r
+>      notmuch_query_t *query;\r
+>      notmuch_messages_t *messages;\r
+>      notmuch_message_t *message;\r
+> -    int i;\r
+>  \r
+>      /* Optimize the query so it excludes messages that already have\r
+>       * the specified set of tags. */\r
+> @@ -124,21 +119,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
+>       notmuch_messages_valid (messages) && ! interrupted;\r
+>       notmuch_messages_move_to_next (messages)) {\r
+>      message = notmuch_messages_get (messages);\r
+> -\r
+> -    notmuch_message_freeze (message);\r
+> -\r
+> -    for (i = 0; tag_ops[i].tag; i++) {\r
+> -        if (tag_ops[i].remove)\r
+> -            notmuch_message_remove_tag (message, tag_ops[i].tag);\r
+> -        else\r
+> -            notmuch_message_add_tag (message, tag_ops[i].tag);\r
+> -    }\r
+> -\r
+> -    notmuch_message_thaw (message);\r
+> -\r
+> -    if (synchronize_flags)\r
+> -        notmuch_message_tags_to_maildir_flags (message);\r
+> -\r
+> +    tag_op_list_apply (message, tag_ops, flags | TAG_FLAG_PRE_OPTIMIZED);\r
+\r
+I think we probably want to check for errors and bail out on them\r
+here. It's a functional change, so it belongs in a follow-up patch. We\r
+haven't done it before, but it'll be more important with batch tagging.\r
+\r
+BR,\r
+Jani.\r
+\r
+\r
+>      notmuch_message_destroy (message);\r
+>      }\r
+>  \r
+> @@ -150,15 +131,13 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,\r
+>  int\r
+>  notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+>  {\r
+> -    tag_operation_t *tag_ops;\r
+> -    int tag_ops_count = 0;\r
+> -    char *query_string;\r
+> +    tag_op_list_t *tag_ops = NULL;\r
+> +    char *query_string = NULL;\r
+>      notmuch_config_t *config;\r
+>      notmuch_database_t *notmuch;\r
+>      struct sigaction action;\r
+> -    notmuch_bool_t synchronize_flags;\r
+> -    int i;\r
+> -    int ret;\r
+> +    tag_op_flag_t tag_flags = TAG_FLAG_NONE;\r
+> +    int ret = 0;\r
+>  \r
+>      /* Setup our handler for SIGINT */\r
+>      memset (&action, 0, sizeof (struct sigaction));\r
+> @@ -167,54 +146,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+>      action.sa_flags = SA_RESTART;\r
+>      sigaction (SIGINT, &action, NULL);\r
+>  \r
+> -    argc--; argv++; /* skip subcommand argument */\r
+> -\r
+> -    /* Array of tagging operations (add or remove), terminated with an\r
+> -     * empty element. */\r
+> -    tag_ops = talloc_array (ctx, tag_operation_t, argc + 1);\r
+> +    tag_ops = tag_op_list_create (ctx);\r
+>      if (tag_ops == NULL) {\r
+>      fprintf (stderr, "Out of memory.\n");\r
+>      return 1;\r
+>      }\r
+>  \r
+> -    for (i = 0; i < argc; i++) {\r
+> -    if (strcmp (argv[i], "--") == 0) {\r
+> -        i++;\r
+> -        break;\r
+> -    }\r
+> -    if (argv[i][0] == '+' || argv[i][0] == '-') {\r
+> -        if (argv[i][0] == '+' && argv[i][1] == '\0') {\r
+> -            fprintf (stderr, "Error: tag names cannot be empty.\n");\r
+> -            return 1;\r
+> -        }\r
+> -        if (argv[i][0] == '+' && argv[i][1] == '-') {\r
+> -            /* This disallows adding the non-removable tag "-" and\r
+> -             * enables notmuch tag to take long options in the\r
+> -             * future. */\r
+> -            fprintf (stderr, "Error: tag names must not start with '-'.\n");\r
+> -            return 1;\r
+> -        }\r
+> -        tag_ops[tag_ops_count].tag = argv[i] + 1;\r
+> -        tag_ops[tag_ops_count].remove = (argv[i][0] == '-');\r
+> -        tag_ops_count++;\r
+> -    } else {\r
+> -        break;\r
+> -    }\r
+> -    }\r
+> -\r
+> -    tag_ops[tag_ops_count].tag = NULL;\r
+> -\r
+> -    if (tag_ops_count == 0) {\r
+> -    fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
+> -    return 1;\r
+> -    }\r
+> -\r
+> -    query_string = query_string_from_args (ctx, argc - i, &argv[i]);\r
+> -\r
+> -    if (*query_string == '\0') {\r
+> -    fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
+> +    if (parse_tag_command_line (ctx, argc - 1, argv + 1,\r
+> +                            &query_string, tag_ops))\r
+>      return 1;\r
+> -    }\r
+>  \r
+>      config = notmuch_config_open (ctx, NULL, NULL);\r
+>      if (config == NULL)\r
+> @@ -224,9 +164,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+>                             NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))\r
+>      return 1;\r
+>  \r
+> -    synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);\r
+> +    if (notmuch_config_get_maildir_synchronize_flags (config))\r
+> +    tag_flags |= TAG_FLAG_MAILDIR_SYNC;\r
+>  \r
+> -    ret = tag_query (ctx, notmuch, query_string, tag_ops, synchronize_flags);\r
+> +    ret = tag_query (ctx, notmuch, query_string, tag_ops, tag_flags);\r
+>  \r
+>      notmuch_database_destroy (notmuch);\r
+>  \r
+> diff --git a/tag-util.c b/tag-util.c\r
+> index 0a4fe78..701d329 100644\r
+> --- a/tag-util.c\r
+> +++ b/tag-util.c\r
+> @@ -45,8 +45,9 @@ illegal_tag (const char *tag, notmuch_bool_t remove)\r
+>      if (*tag == '\0' && ! remove)\r
+>      return "empty tag forbidden";\r
+>  \r
+> -    /* This disallows adding the non-removable tag "-" and\r
+> -     * enables notmuch tag to take long options more easily.\r
+> +    /* This disallows adding tags starting with "-", in particular the\r
+> +     * non-removable tag "-" and enables notmuch tag to take long\r
+> +     * options more easily.\r
+>       */\r
+>  \r
+>      if (*tag == '-' && ! remove)\r
+> @@ -157,6 +158,52 @@ parse_tag_line (void *ctx, char *line,\r
+>      return ret;\r
+>  }\r
+>  \r
+> +tag_parse_status_t\r
+> +parse_tag_command_line (void *ctx, int argc, char **argv,\r
+> +                    char **query_str, tag_op_list_t *tag_ops)\r
+> +{\r
+> +\r
+> +    int i;\r
+> +\r
+> +    tag_op_list_reset (tag_ops);\r
+> +\r
+> +    for (i = 0; i < argc; i++) {\r
+> +    if (strcmp (argv[i], "--") == 0) {\r
+> +        i++;\r
+> +        break;\r
+> +    }\r
+> +\r
+> +    if (argv[i][0] != '+' && argv[i][0] != '-')\r
+> +        break;\r
+> +\r
+> +    notmuch_bool_t is_remove = argv[i][0] == '-';\r
+> +    const char *msg;\r
+> +\r
+> +    msg = illegal_tag (argv[i] + 1, is_remove);\r
+> +    if (msg) {\r
+> +        fprintf (stderr, "Error: %s", msg);\r
+> +        return TAG_PARSE_INVALID;\r
+> +    }\r
+> +\r
+> +    tag_op_list_append (tag_ops, argv[i] + 1, is_remove);\r
+> +    }\r
+> +\r
+> +    if (tag_op_list_size (tag_ops) == 0) {\r
+> +    fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");\r
+> +    return TAG_PARSE_INVALID;\r
+> +    }\r
+> +\r
+> +    *query_str = query_string_from_args (ctx, argc - i, &argv[i]);\r
+> +\r
+> +    if (*query_str == NULL || **query_str == '\0') {\r
+> +    fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");\r
+> +    return TAG_PARSE_INVALID;\r
+> +    }\r
+> +\r
+> +    return TAG_PARSE_SUCCESS;\r
+> +}\r
+> +\r
+> +\r
+>  static inline void\r
+>  message_error (notmuch_message_t *message,\r
+>             notmuch_status_t status,\r
+> diff --git a/tag-util.h b/tag-util.h\r
+> index c07bfde..246de85 100644\r
+> --- a/tag-util.h\r
+> +++ b/tag-util.h\r
+> @@ -72,6 +72,21 @@ parse_tag_line (void *ctx, char *line,\r
+>              tag_op_flag_t flags,\r
+>              char **query_str, tag_op_list_t *ops);\r
+>  \r
+> +\r
+> +\r
+> +/* Parse a command line of the following format:\r
+> + *\r
+> + * +<tag>|-<tag> [...] [--] <search-terms>\r
+> + *\r
+> + * Output Parameters:\r
+> + *  ops     contains a list of tag operations\r
+> + *  query_str the search terms.\r
+> + */\r
+> +\r
+> +tag_parse_status_t\r
+> +parse_tag_command_line (void *ctx, int argc, char **argv,\r
+> +                    char **query_str, tag_op_list_t *ops);\r
+> +\r
+>  /*\r
+>   * Create an empty list of tag operations\r
+>   *\r
+> -- \r
+> 1.7.10.4\r
+>\r
+> _______________________________________________\r
+> notmuch mailing list\r
+> notmuch@notmuchmail.org\r
+> http://notmuchmail.org/mailman/listinfo/notmuch\r