typedef struct {
int output_is_a_tty;
- int verbose;
- int debug;
+ notmuch_bool_t verbose;
+ notmuch_bool_t debug;
const char **new_tags;
size_t new_tags_length;
const char **new_ignore;
}
db_mtime = directory ? notmuch_directory_get_mtime (directory) : 0;
+ /* If the directory is unchanged from our last scan and has no
+ * sub-directories, then return without scanning it at all. In
+ * some situations, skipping the scan can substantially reduce the
+ * cost of notmuch new, especially since the huge numbers of files
+ * in Maildirs make scans expensive, but all files live in leaf
+ * directories.
+ *
+ * To check for sub-directories, we borrow a trick from find,
+ * kpathsea, and many other UNIX tools: since a directory's link
+ * count is the number of sub-directories (specifically, their
+ * '..' entries) plus 2 (the link from the parent and the link for
+ * '.'). This check is safe even on weird file systems, since
+ * file systems that can't compute this will return 0 or 1. This
+ * is safe even on *really* weird file systems like HFS+ that
+ * mistakenly return the total number of directory entries, since
+ * that only inflates the count beyond 2.
+ */
+ if (directory && fs_mtime == db_mtime && st.st_nlink == 2) {
+ /* There's one catch: pass 1 below considers symlinks to
+ * directories to be directories, but these don't increase the
+ * file system link count. So, only bail early if the
+ * database agrees that there are no sub-directories. */
+ db_subdirs = notmuch_directory_get_child_directories (directory);
+ if (!notmuch_filenames_valid (db_subdirs))
+ goto DONE;
+ notmuch_filenames_destroy (db_subdirs);
+ db_subdirs = NULL;
+ }
+
/* If the database knows about this directory, then we sort based
* on strcmp to match the database sorting. Otherwise, we can do
* inode-based sorting for faster filesystem operation. */
}
int
-notmuch_new_command (void *ctx, int argc, char *argv[])
+notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
{
- notmuch_config_t *config;
notmuch_database_t *notmuch;
add_files_state_t add_files_state;
double elapsed;
char *dot_notmuch_path;
struct sigaction action;
_filename_node_t *f;
+ int opt_index;
int i;
notmuch_bool_t timer_is_active = FALSE;
- notmuch_bool_t run_hooks = TRUE;
+ notmuch_bool_t no_hooks = FALSE;
- add_files_state.verbose = 0;
- add_files_state.debug = 0;
+ add_files_state.verbose = FALSE;
+ add_files_state.debug = FALSE;
add_files_state.output_is_a_tty = isatty (fileno (stdout));
- argc--; argv++; /* skip subcommand argument */
+ notmuch_opt_desc_t options[] = {
+ { NOTMUCH_OPT_BOOLEAN, &add_files_state.verbose, "verbose", 'v', 0 },
+ { NOTMUCH_OPT_BOOLEAN, &add_files_state.debug, "debug", 'd', 0 },
+ { NOTMUCH_OPT_BOOLEAN, &no_hooks, "no-hooks", 'n', 0 },
+ { 0, 0, 0, 0, 0 }
+ };
- for (i = 0; i < argc && argv[i][0] == '-'; i++) {
- if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {
- add_files_state.verbose = 1;
- } else if (strcmp (argv[i], "--debug") == 0) {
- add_files_state.debug = 1;
- } else if (strcmp (argv[i], "--no-hooks") == 0) {
- run_hooks = FALSE;
- } else {
- fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
- return 1;
- }
- }
- config = notmuch_config_open (ctx, NULL, NULL);
- if (config == NULL)
- return 1;
+ opt_index = parse_arguments (argc, argv, options, 1);
+ if (opt_index < 0)
+ return EXIT_FAILURE;
add_files_state.new_tags = notmuch_config_get_new_tags (config, &add_files_state.new_tags_length);
add_files_state.new_ignore = notmuch_config_get_new_ignore (config, &add_files_state.new_ignore_length);
add_files_state.synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
db_path = notmuch_config_get_database_path (config);
- if (run_hooks) {
+ if (!no_hooks) {
ret = notmuch_run_hook (db_path, "pre-new");
if (ret)
- return ret;
+ return EXIT_FAILURE;
}
- dot_notmuch_path = talloc_asprintf (ctx, "%s/%s", db_path, ".notmuch");
+ dot_notmuch_path = talloc_asprintf (config, "%s/%s", db_path, ".notmuch");
if (stat (dot_notmuch_path, &st)) {
int count;
count = 0;
count_files (db_path, &count, &add_files_state);
if (interrupted)
- return 1;
+ return EXIT_FAILURE;
printf ("Found %d total files (that's not much mail).\n", count);
if (notmuch_database_create (db_path, ¬much))
- return 1;
+ return EXIT_FAILURE;
add_files_state.total_files = count;
} else {
if (notmuch_database_open (db_path, NOTMUCH_DATABASE_MODE_READ_WRITE,
¬much))
- return 1;
+ return EXIT_FAILURE;
if (notmuch_database_needs_upgrade (notmuch)) {
printf ("Welcome to a new version of notmuch! Your database will now be upgraded.\n");
}
if (notmuch == NULL)
- return 1;
+ return EXIT_FAILURE;
/* Setup our handler for SIGINT. We do this after having
* potentially done a database upgrade we this interrupt handler
add_files_state.removed_messages = add_files_state.renamed_messages = 0;
gettimeofday (&add_files_state.tv_start, NULL);
- add_files_state.removed_files = _filename_list_create (ctx);
- add_files_state.removed_directories = _filename_list_create (ctx);
- add_files_state.directory_mtimes = _filename_list_create (ctx);
+ add_files_state.removed_files = _filename_list_create (config);
+ add_files_state.removed_directories = _filename_list_create (config);
+ add_files_state.directory_mtimes = _filename_list_create (config);
if (! debugger_is_active () && add_files_state.output_is_a_tty
&& ! add_files_state.verbose) {
gettimeofday (&tv_start, NULL);
for (f = add_files_state.removed_directories->head, i = 0; f && !interrupted; f = f->next, i++) {
- ret = _remove_directory (ctx, notmuch, f->filename, &add_files_state);
+ ret = _remove_directory (config, notmuch, f->filename, &add_files_state);
if (ret)
goto DONE;
if (do_print_progress) {
notmuch_database_destroy (notmuch);
- if (run_hooks && !ret && !interrupted)
+ if (!no_hooks && !ret && !interrupted)
ret = notmuch_run_hook (db_path, "post-new");
- return ret || interrupted;
+ return ret || interrupted ? EXIT_FAILURE : EXIT_SUCCESS;
}