Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id EE8AF431FD0 for ; Tue, 5 Jul 2011 14:42:47 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -0.7 X-Spam-Level: X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UdcDcrTaTf-R for ; Tue, 5 Jul 2011 14:42:47 -0700 (PDT) Received: from dmz-mailsec-scanner-5.mit.edu (DMZ-MAILSEC-SCANNER-5.MIT.EDU [18.7.68.34]) by olra.theworths.org (Postfix) with ESMTP id 26639431FB6 for ; Tue, 5 Jul 2011 14:42:47 -0700 (PDT) X-AuditID: 12074422-b7b19ae000000a1c-73-4e13854a7c62 Received: from mailhub-auth-1.mit.edu ( [18.9.21.35]) by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP id A9.BE.02588.A45831E4; Tue, 5 Jul 2011 17:42:34 -0400 (EDT) Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103]) by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id p65LgkYh032021; Tue, 5 Jul 2011 17:42:46 -0400 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91]) (authenticated bits=0) (User authenticated as amdragon@ATHENA.MIT.EDU) by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id p65LgiC5024765 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); Tue, 5 Jul 2011 17:42:45 -0400 (EDT) Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.72) (envelope-from ) id 1QeDO7-00040f-00; Tue, 05 Jul 2011 17:42:35 -0400 Date: Tue, 5 Jul 2011 17:42:34 -0400 From: Austin Clements To: Pieter Praet Subject: Re: [PROTO] possible solution for "Race condition for '*' command" Message-ID: <20110705214234.GA15360@mit.edu> References: <20110703171743.GL15901@mit.edu> <1309762318-4530-1-git-send-email-pieter@praet.org> <87sjqldgr7.fsf@praet.org> <87iprg7dm0.fsf@praet.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87iprg7dm0.fsf@praet.org> User-Agent: Mutt/1.5.20 (2009-06-14) X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpileLIzCtJLcpLzFFi42IR4hRV1vVqFfYz2D9L2uL6zZnMFr9f32B2 YPJ4tuoWs0fHvsusAUxRXDYpqTmZZalF+nYJXBn3L35jLbioUzH/SnQD4w2lLkZODgkBE4kX nz8yQ9hiEhfurWfrYuTiEBLYxyhxfno/E4SznlGi+WMPK4Rzgkni8NlbjCAtQgJLGCUmrDMF sVkEVCT6/m0HG8UmoCGxbf9ysBoRAWWJ009+soPYzAJaEls3fgCLCwt4S3x6OpcFxOYV0JFo 3f6dDWLmdUaJufcsIeKCEidnPmGB6b3x7yXQRRxAtrTE8n8cIGFOAXWJjf/3go0UBTrh2v52 tgmMQrOQdM9C0j0LoXsBI/MqRtmU3Crd3MTMnOLUZN3i5MS8vNQiXVO93MwSvdSU0k2MoKBm d1HawfjzoNIhRgEORiUe3hVGwn5CrIllxZW5hxglOZiURHkNWoBCfEn5KZUZicUZ8UWlOanF hxglOJiVRHgjLYByvCmJlVWpRfkwKWkOFiVx3hLv/75CAumJJanZqakFqUUwWRkODiUJ3tUg QwWLUtNTK9Iyc0oQ0kwcnCDDeYCGh4LU8BYXJOYWZ6ZD5E8xKkqJ814ESQiAJDJK8+B6YUnn FaM40CvCvNdBqniACQuu+xXQYCagwVaJgiCDSxIRUlINjOFpr69I71fiXHbX8K5tkVFX/1TO tXeT1ObaZOUzP/Od86Mn3nKZmeLrO1uuhPnxNLP+mu6+lkHq8CJNZeOe+TKb8lmjS4NWXj7y YptPGNvGB5yv16ZqbPaaN+P6bbkqteY+zdU7+I/dPb73hWAnb7Plt7dTD2VUdIZdOzxnd4/+ WYcZ/GmVn5VYijMSDbWYi4oTAdx/9UMVAwAA Cc: Notmuch Mail X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jul 2011 21:42:48 -0000 Quoth Pieter Praet on Jul 05 at 9:04 pm: > On Mon, 04 Jul 2011 20:48:12 +0200, Pieter Praet wrote: > > On Mon, 04 Jul 2011 13:56:26 -0400, Austin Clements wrote: > > > I should probably emit two lists per thread: one of matched IDs and > > > one of unmatched IDs. Tagging a region can then operate on the > > > concatenation of these, while * can operate only on the matched > > > lists. This should be easy to do. I'll send an updated patch when I'm > > > back at a computer. > > > > The matched MsgIds will be sufficient, as we'll want to operate on > > either the matched messages or the entire thread (for which the > > `thread-id' property is already present). > > > > Can't think of a use case for non-matched messages right now, > > but if required, we'll just use `set-exclusive-or'. > > Wasn't thinking clearly: > > You're right, we *will* be needing both a list of matched as well as one > of unmatched Message-Id's per result. Otherwise there would still be a > potential race condition when tagging with +/-. Yes, exactly. (I had originally thought this race was a strict superset of the '*' race; I now realize that's not the case, but they're related enough that they might as well be addressed together.) Below is an updated patch that separates the matched and unmatched ID's (it's ugly, but no point in cleaning it up since it's a prototype). Now the tag list on each search line is followed by something that looks like (id:x or id:y) or id:z or just (id:x or id:y) where the parenthesized part of the query is for the matched messages and the (possibly empty) unparenthesized part is for the non-matched messages. This is designed to be easy for emacs to parse: grab just the parenthesized part for the queries used by '*' and the whole thing for region tagging queries. This should also eliminate corner cases for pasting together multiple queries with "or". diff --git a/notmuch-search.c b/notmuch-search.c index faccaf7..2288eb7 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -190,6 +190,28 @@ format_thread_json (const void *ctx, talloc_free (ctx_quote); } +static void +show_message_ids (notmuch_messages_t *messages, const char **first, + notmuch_bool_t match) +{ + notmuch_message_t *message; + + for (; + notmuch_messages_valid (messages); + notmuch_messages_move_to_next (messages)) { + message = notmuch_messages_get (messages); + if (notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) == match) { + if (*first) + fputs (*first, stdout); + else + fputs (" or ", stdout); + *first = NULL; + printf ("id:\"%s\"", notmuch_message_get_message_id (message)); + } + show_message_ids (notmuch_message_get_replies (message), first, match); + } +} + static int do_search_threads (const search_format_t *format, notmuch_query_t *query, @@ -252,6 +274,22 @@ do_search_threads (const search_format_t *format, fputs (format->tag_end, stdout); + if (format == &format_text) { + notmuch_messages_t *toplevel; + const char *first; + + toplevel = notmuch_thread_get_toplevel_messages (thread); + first = " ("; + show_message_ids (toplevel, &first, TRUE); + if (first) + INTERNAL_ERROR ("No matched messages"); + fputs (")", stdout); + + toplevel = notmuch_thread_get_toplevel_messages (thread); + first = " or "; + show_message_ids (toplevel, &first, FALSE); + } + fputs (format->item_end, stdout); } diff --git a/notmuch-tag.c b/notmuch-tag.c index 6204ae3..5609d02 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -30,6 +30,36 @@ handle_sigint (unused (int sig)) interrupted = 1; } +static char* +query_string_from_stdin (void *ctx) +{ + char *query_string = talloc_strdup (ctx, ""); + char buf[4096]; + + if (query_string == NULL) { + fprintf (stderr, "Out of memory.\n"); + return NULL; + } + + while (1) { + ssize_t r = read(0, buf, sizeof (buf)); + if (r < 0) { + fprintf (stderr, "Error reading from stdin: %s\n", + strerror (errno)); + return NULL; + } else if (r == 0) { + break; + } + query_string = talloc_strndup_append (query_string, buf, r); + if (!query_string) { + fprintf (stderr, "Out of memory.\n"); + return NULL; + } + } + + return query_string; +} + int notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[])) { @@ -44,6 +74,7 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[])) notmuch_message_t *message; struct sigaction action; notmuch_bool_t synchronize_flags; + notmuch_bool_t use_stdin = FALSE; int i; /* Setup our handler for SIGINT */ @@ -70,7 +101,9 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[])) i++; break; } - if (argv[i][0] == '+') { + if (STRNCMP_LITERAL (argv[i], "--stdin") == 0) { + use_stdin = TRUE; + } else if (argv[i][0] == '+') { add_tags[add_tags_count++] = i; } else if (argv[i][0] == '-') { remove_tags[remove_tags_count++] = i; @@ -84,7 +117,13 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[])) return 1; } - query_string = query_string_from_args (ctx, argc - i, &argv[i]); + if (use_stdin) + query_string = query_string_from_stdin (ctx); + else + query_string = query_string_from_args (ctx, argc - i, &argv[i]); + + if (!query_string) + return 1; if (*query_string == '\0') { fprintf (stderr, "Error: notmuch tag requires at least one search term.\n");