Re: [PATCH] test: remove ".sh" extension from the recently added Emacs tests
[notmuch-archives.git] / b8 / bf5130bc1f1f999843a2326288e22a6e050b7d
1 Return-Path: <bremner@unb.ca>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 0A41040D152\r
6         for <notmuch@notmuchmail.org>; Sun, 24 Oct 2010 14:02:08 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -2.6\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-2.6 tagged_above=-999 required=5\r
12         tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7] autolearn=ham\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id Re-v-T3Ks9Tz for <notmuch@notmuchmail.org>;\r
16         Sun, 24 Oct 2010 14:01:51 -0700 (PDT)\r
17 Received: from tempo.its.unb.ca (tempo.its.unb.ca [131.202.1.21])\r
18         by olra.theworths.org (Postfix) with ESMTP id BBEC840D157\r
19         for <notmuch@notmuchmail.org>; Sun, 24 Oct 2010 14:01:14 -0700 (PDT)\r
20 Received: from rocinante.cs.unb.ca\r
21         (fctnnbsc30w-142167176217.pppoe-dynamic.High-Speed.nb.bellaliant.net\r
22         [142.167.176.217]) (authenticated bits=0)\r
23         by tempo.its.unb.ca (8.13.8/8.13.8) with ESMTP id o9OL1BEg017810\r
24         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO);\r
25         Sun, 24 Oct 2010 18:01:14 -0300\r
26 Received: from bremner by rocinante.cs.unb.ca with local (Exim 4.72)\r
27         (envelope-from <bremner@unb.ca>)\r
28         id 1PA7gl-0006Ok-Ci; Sun, 24 Oct 2010 18:01:11 -0300\r
29 From: david@tethera.net\r
30 To: notmuch@notmuchmail.org\r
31 Subject: [PATCH 1/4] Initial implementation of low level logging routines.\r
32 Date: Sun, 24 Oct 2010 18:01:03 -0300\r
33 Message-Id: <1287954066-24512-2-git-send-email-david@tethera.net>\r
34 X-Mailer: git-send-email 1.7.1\r
35 In-Reply-To: <1286803617-17328-1-git-send-email-david@tethera.net>\r
36 References: <1286803617-17328-1-git-send-email-david@tethera.net>\r
37 Cc: David Bremner <bremner@unb.ca>\r
38 X-BeenThere: notmuch@notmuchmail.org\r
39 X-Mailman-Version: 2.1.13\r
40 Precedence: list\r
41 List-Id: "Use and development of the notmuch mail system."\r
42         <notmuch.notmuchmail.org>\r
43 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
44         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
45 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
46 List-Post: <mailto:notmuch@notmuchmail.org>\r
47 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
48 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
49         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
50 X-List-Received-Date: Sun, 24 Oct 2010 21:02:08 -0000\r
51 \r
52 From: David Bremner <bremner@unb.ca>\r
53 \r
54 notmuch_log_open: open a log file; return an opaque "log descriptor"\r
55 \r
56 notmuch_log_words: log words, escaping spaces and newlines, and appending a newline.\r
57 \r
58 Log format is space delimited, and line oriented.  Escaping log text\r
59 is currently based on a slightly simplified version of\r
60 json_quote_chararray in ../json.c. This is probably overkill.\r
61 \r
62 notmuch_log_transaction_(start|finish): log a transaction identifier\r
63 and depth.\r
64 \r
65 Nested transactions are supported, so that this aligns with\r
66 notmuch_message_(freeze|thaw).  The are not too well tested though,\r
67 since I don't know when they arise.\r
68 ---\r
69  lib/Makefile.local |    1 +\r
70  lib/log-private.h  |   13 +++\r
71  lib/log.c          |  289 ++++++++++++++++++++++++++++++++++++++++++++++++++++\r
72  lib/notmuch.h      |   23 ++++\r
73  notmuch-client.h   |    4 +\r
74  notmuch-config.c   |   15 +++\r
75  6 files changed, 345 insertions(+), 0 deletions(-)\r
76  create mode 100644 lib/log-private.h\r
77  create mode 100644 lib/log.c\r
78 \r
79 diff --git a/lib/Makefile.local b/lib/Makefile.local\r
80 index a60ef98..d7e8f41 100644\r
81 --- a/lib/Makefile.local\r
82 +++ b/lib/Makefile.local\r
83 @@ -46,6 +46,7 @@ extra_cflags += -I$(dir) -fPIC\r
84  libnotmuch_c_srcs =            \\r
85         $(notmuch_compat_srcs)  \\r
86         $(dir)/libsha1.c        \\r
87 +       $(dir)/log.c            \\r
88         $(dir)/message-file.c   \\r
89         $(dir)/messages.c       \\r
90         $(dir)/sha1.c           \\r
91 diff --git a/lib/log-private.h b/lib/log-private.h\r
92 new file mode 100644\r
93 index 0000000..1af05dd\r
94 --- /dev/null\r
95 +++ b/lib/log-private.h\r
96 @@ -0,0 +1,13 @@\r
97 +\r
98 +#ifndef NOTMUCH_LOG_PRIVATE_H\r
99 +#define NOTMUCH_LOG_PRIVATE_H\r
100 +#include "notmuch.h"\r
101 +struct _notmuch_log {\r
102 +  int file_desc;\r
103 +  char *buffer;\r
104 +  char *txn_id;\r
105 +  int txn_depth;\r
106 +  notmuch_log_buffering_t buffering;\r
107 +};\r
108 +\r
109 +#endif\r
110 diff --git a/lib/log.c b/lib/log.c\r
111 new file mode 100644\r
112 index 0000000..31f1e62\r
113 --- /dev/null\r
114 +++ b/lib/log.c\r
115 @@ -0,0 +1,289 @@\r
116 +\r
117 +/* notmuch - Not much of an email program, (just index and search)\r
118 + *\r
119 + * Copyright © 2010 David Bremner\r
120 + *\r
121 + * This program is free software: you can redistribute it and/or modify\r
122 + * it under the terms of the GNU General Public License as published by\r
123 + * the Free Software Foundation, either version 3 of the License, or\r
124 + * (at your option) any later version.\r
125 + *\r
126 + * This program is distributed in the hope that it will be useful,\r
127 + * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
128 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
129 + * GNU General Public License for more details.\r
130 + *\r
131 + * You should have received a copy of the GNU General Public License\r
132 + * along with this program.  If not, see http://www.gnu.org/licenses/ .\r
133 + *\r
134 + * Author: David Bremner <david@tethera.net>\r
135 + */\r
136 +\r
137 +#include <sys/types.h>\r
138 +#include <sys/stat.h>\r
139 +#include <fcntl.h>\r
140 +#include <unistd.h>\r
141 +#include <errno.h>\r
142 +#include <string.h>\r
143 +#include <talloc.h>\r
144 +#include <stdarg.h>\r
145 +\r
146 +#include "log-private.h"\r
147 +#include "notmuch.h"\r
148 +\r
149 +/*\r
150 + * Return a file descriptor to the open log file, or -1 if an error\r
151 + * occurs.\r
152 + *\r
153 + */\r
154 +\r
155 +notmuch_log_t *\r
156 +notmuch_log_open (void *ctx,const char *path, notmuch_log_buffering_t buffering)\r
157 +{\r
158 +    int fd;\r
159 +    notmuch_log_t *log;\r
160 +\r
161 +    log=talloc (ctx, notmuch_log_t);\r
162 +    if (log==NULL)\r
163 +       return NULL;\r
164 +\r
165 +    fd = open (path, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);\r
166 +    if (fd < 0) {\r
167 +       fprintf (stderr, "Failed to open %s: %s\n",\r
168 +                path, strerror (errno));\r
169 +       return NULL;\r
170 +    }\r
171 +\r
172 +    log->file_desc = fd;\r
173 +    log->buffer = NULL;\r
174 +    log->txn_id = NULL;\r
175 +    log->txn_depth = 0;\r
176 +    log->buffering = buffering;\r
177 +    return log;\r
178 +}\r
179 +\r
180 +static notmuch_status_t\r
181 +_log_write (int file_desc, const char *buffer, size_t len){\r
182 +\r
183 +    struct flock lock;\r
184 +\r
185 +    lock.l_type = F_WRLCK;\r
186 +    lock.l_whence = SEEK_SET;\r
187 +    lock.l_start = 0;\r
188 +    lock.l_len = 0;\r
189 +\r
190 +    if (fcntl (file_desc, F_SETLKW, &lock) != 0) {\r
191 +       fprintf (stderr, "Failed to lock  %s\n",\r
192 +                strerror (errno));\r
193 +\r
194 +       return NOTMUCH_STATUS_FILE_ERROR;\r
195 +    }\r
196 +\r
197 +    while (len > 0)\r
198 +    {\r
199 +       int written;\r
200 +\r
201 +       written = write(file_desc, buffer, len);\r
202 +       if (written < 0 || (written == 0 && errno !=0))\r
203 +       {\r
204 +           fprintf (stderr, "Failed to write %zd characters: %s\n",\r
205 +                    len, strerror (errno));\r
206 +\r
207 +           return NOTMUCH_STATUS_FILE_ERROR;\r
208 +       }\r
209 +\r
210 +       len -= written;\r
211 +       buffer += written;\r
212 +\r
213 +    }\r
214 +\r
215 +    if (fdatasync (file_desc) != 0) {\r
216 +       fprintf (stderr, "Failed to sync:  %s\n",\r
217 +                strerror (errno));\r
218 +\r
219 +       return NOTMUCH_STATUS_FILE_ERROR;\r
220 +    }\r
221 +\r
222 +    lock.l_type=F_UNLCK;\r
223 +\r
224 +    if (fcntl (file_desc, F_SETLK, &lock) != 0) {\r
225 +       fprintf (stderr, "Failed to unlock:  %s\n",\r
226 +                strerror (errno));\r
227 +\r
228 +       return NOTMUCH_STATUS_FILE_ERROR;\r
229 +    }\r
230 +\r
231 +    return NOTMUCH_STATUS_SUCCESS;\r
232 +}\r
233 +\r
234 +void\r
235 +notmuch_log_sync (notmuch_log_t *log)\r
236 +{\r
237 +    if (log->buffer) {\r
238 +       _log_write(log->file_desc, log->buffer, strlen (log->buffer));\r
239 +       talloc_free(log->buffer);\r
240 +       log->buffer=NULL;\r
241 +    }\r
242 +\r
243 +};\r
244 +\r
245 +\r
246 +/* This function was derived from the print_string_ptr function of\r
247 + * cJSON (http://cjson.sourceforge.net/) and is used by permission of\r
248 + * the following license:\r
249 + *\r
250 + * Copyright (c) 2009 Dave Gamble\r
251 + *\r
252 + * Permission is hereby granted, free of charge, to any person obtaining a copy\r
253 + * of this software and associated documentation files (the "Software"), to deal\r
254 + * in the Software without restriction, including without limitation the rights\r
255 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
256 + * copies of the Software, and to permit persons to whom the Software is\r
257 + * furnished to do so, subject to the following conditions:\r
258 + *\r
259 + * The above copyright notice and this permission notice shall be included in\r
260 + * all copies or substantial portions of the Software.\r
261 + *\r
262 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
263 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
264 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
265 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
266 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
267 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
268 + * THE SOFTWARE.\r
269 + */\r
270 +\r
271 +static char *\r
272 +_log_escape_chararray(const void *ctx, const char *str, const size_t len)\r
273 +{\r
274 +    const char *ptr;\r
275 +    char *ptr2;\r
276 +    char *out;\r
277 +    size_t loop;\r
278 +    size_t required;\r
279 +\r
280 +    for (loop = 0, required = 0, ptr = str;\r
281 +        loop < len;\r
282 +        loop++, required++, ptr++) {\r
283 +       if ((unsigned char)(*ptr) <= ' ')\r
284 +           required++;\r
285 +    }\r
286 +\r
287 +    /*\r
288 +     * + 1 for trailing NULL.\r
289 +     */\r
290 +    out = talloc_array (ctx, char, required + 1);\r
291 +\r
292 +    ptr = str;\r
293 +    ptr2 = out;\r
294 +\r
295 +    for (loop = 0; loop < len; loop++) {\r
296 +       if ((unsigned char)(*ptr) > 32 && *ptr != '\"' && *ptr != '\\') {\r
297 +               *ptr2++ = *ptr++;\r
298 +           } else {\r
299 +               *ptr2++ = '\\';\r
300 +               switch (*ptr++) {\r
301 +                   case ' ':   *ptr2++ = ' ';  break;\r
302 +                   case '\\':  *ptr2++ = '\\'; break;\r
303 +                   case '\b':  *ptr2++ = 'b';  break;\r
304 +                   case '\f':  *ptr2++ = 'f';  break;\r
305 +                   case '\n':  *ptr2++ = 'n';  break;\r
306 +                   case '\r':  *ptr2++ = 'r';  break;\r
307 +                   case '\t':  *ptr2++ = 't';  break;\r
308 +                   default:     ptr2--;        break;\r
309 +               }\r
310 +           }\r
311 +    }\r
312 +    *ptr2++ = '\0';\r
313 +\r
314 +    return out;\r
315 +}\r
316 +\r
317 +static char*\r
318 +_log_escape_string (void *ctx, const char *str)\r
319 +{\r
320 +    return _log_escape_chararray (ctx, str, strlen(str));\r
321 +}\r
322 +\r
323 +/*\r
324 + * Log a series of strings as a space delimited line.  Spaces and\r
325 + * backslashes will be escaped by adding a backslash in front.\r
326 + */\r
327 +\r
328 +static notmuch_status_t\r
329 +_log_append_string (notmuch_log_t *log, const char *str)\r
330 +{\r
331 +    if (log->buffer == NULL) {\r
332 +       log->buffer = talloc_strdup (log, str);\r
333 +    } else {\r
334 +       log->buffer = talloc_strdup_append (log->buffer, str);\r
335 +    }\r
336 +\r
337 +    if (log->buffer == NULL){\r
338 +       return NOTMUCH_STATUS_OUT_OF_MEMORY;\r
339 +    }\r
340 +\r
341 +    if (log->buffering == NOTMUCH_LOG_BUFFER_NONE)\r
342 +       notmuch_log_sync(log);\r
343 +\r
344 +    return NOTMUCH_STATUS_SUCCESS;\r
345 +}\r
346 +\r
347 +\r
348 +/*\r
349 + *  Log a null terminated list of strings as a single space delimited log line.\r
350 + *  spaces and newlines are escaped.\r
351 + */\r
352 +\r
353 +void\r
354 +notmuch_log_words (notmuch_log_t *log, const char *word, ...)\r
355 +{\r
356 +    va_list args;\r
357 +    const char *str;\r
358 +    char *timestamp;\r
359 +\r
360 +    timestamp = talloc_asprintf (log, "%ld", (long)time(NULL));\r
361 +    _log_append_string(log,timestamp);\r
362 +    talloc_free(timestamp);\r
363 +\r
364 +    va_start (args, word);\r
365 +\r
366 +    for (str = word; str != NULL; str = va_arg (args, const char *)) {\r
367 +       _log_append_string (log, " ");\r
368 +       _log_append_string(log, _log_escape_string (log, str));\r
369 +    }\r
370 +\r
371 +    va_end(args);\r
372 +\r
373 +    _log_append_string(log, "\n");\r
374 +    if (log->buffering <= NOTMUCH_LOG_BUFFER_LINE)\r
375 +       notmuch_log_sync(log);\r
376 +\r
377 +};\r
378 +\r
379 +void\r
380 +notmuch_log_start_transaction (notmuch_log_t *log)\r
381 +{\r
382 +    /* XXX This should probably be something like a uuid */\r
383 +    if (log->txn_depth == 0) {\r
384 +       log->txn_id = talloc_asprintf (log, "%ld", random());\r
385 +    }\r
386 +    log->txn_depth++;\r
387 +\r
388 +    notmuch_log_words(log,"TX_START",\r
389 +                     talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));\r
390 +};\r
391 +\r
392 +void\r
393 +notmuch_log_finish_transaction (notmuch_log_t *log)\r
394 +{\r
395 +    notmuch_log_words(log,"TX_END",\r
396 +                     talloc_asprintf (log, "%s.%d", log->txn_id, log->txn_depth));\r
397 +\r
398 +    log->txn_depth--;\r
399 +\r
400 +    if (log->txn_depth == 0){\r
401 +       talloc_free (log->txn_id);\r
402 +       log->txn_id = NULL;\r
403 +    }\r
404 +};\r
405 diff --git a/lib/notmuch.h b/lib/notmuch.h\r
406 index 505ad19..1da84aa 100644\r
407 --- a/lib/notmuch.h\r
408 +++ b/lib/notmuch.h\r
409 @@ -119,6 +119,7 @@ typedef struct _notmuch_message notmuch_message_t;\r
410  typedef struct _notmuch_tags notmuch_tags_t;\r
411  typedef struct _notmuch_directory notmuch_directory_t;\r
412  typedef struct _notmuch_filenames notmuch_filenames_t;\r
413 +typedef struct _notmuch_log notmuch_log_t;\r
414  \r
415  /* Create a new, empty notmuch database located at 'path'.\r
416   *\r
417 @@ -1123,6 +1124,28 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);\r
418  void\r
419  notmuch_filenames_destroy (notmuch_filenames_t *filenames);\r
420  \r
421 +\r
422 +typedef enum _notmuch_log_buffer {\r
423 +  NOTMUCH_LOG_BUFFER_NONE = 0,\r
424 +  NOTMUCH_LOG_BUFFER_LINE = 1,\r
425 +  NOTMUCH_LOG_BUFFER_USER = 2\r
426 +} notmuch_log_buffering_t;\r
427 +\r
428 +notmuch_log_t *\r
429 +notmuch_log_open (void *ctx, const char *path, notmuch_log_buffering_t buffering);\r
430 +\r
431 +\r
432 +void\r
433 +notmuch_log_sync (notmuch_log_t *log);\r
434 +\r
435 +void\r
436 +notmuch_log_words (notmuch_log_t *log, const char *word, ...);\r
437 +void\r
438 +notmuch_log_start_transaction (notmuch_log_t *log);\r
439 +\r
440 +void\r
441 +notmuch_log_finish_transaction (notmuch_log_t *log);\r
442 +\r
443  NOTMUCH_END_DECLS\r
444  \r
445  #endif\r
446 diff --git a/notmuch-client.h b/notmuch-client.h\r
447 index 20be43b..0be679d 100644\r
448 --- a/notmuch-client.h\r
449 +++ b/notmuch-client.h\r
450 @@ -191,6 +191,10 @@ notmuch_config_set_new_tags (notmuch_config_t *config,\r
451                              const char *new_tags[],\r
452                              size_t length);\r
453  \r
454 +const char *\r
455 +notmuch_config_get_log_path (notmuch_config_t *config,\r
456 +                            const char *name);\r
457 +\r
458  notmuch_bool_t\r
459  debugger_is_active (void);\r
460  \r
461 diff --git a/notmuch-config.c b/notmuch-config.c\r
462 index cf30603..c01e8f4 100644\r
463 --- a/notmuch-config.c\r
464 +++ b/notmuch-config.c\r
465 @@ -562,3 +562,18 @@ notmuch_config_set_new_tags (notmuch_config_t *config,\r
466      config->new_tags = NULL;\r
467  }\r
468  \r
469 +const char *\r
470 +notmuch_config_get_log_path (notmuch_config_t *config, const char *name)\r
471 +{\r
472 +    char *path, *rpath;\r
473 +\r
474 +    path= g_key_file_get_string (config->key_file,\r
475 +                                "log", name, NULL);\r
476 +    if (path != NULL) {\r
477 +       rpath = talloc_strdup (config, path);\r
478 +       free (path);\r
479 +       return rpath;\r
480 +    } else {\r
481 +       return NULL;\r
482 +    }\r
483 +}\r
484 -- \r
485 1.7.1\r
486 \r