From 40334d2dec0545100edcca403d50ad6b1b015a9a Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sat, 25 Apr 2009 15:39:55 +0200 Subject: Update mode By doing update, cgg will check the output structure for missing files and re-generate them as necessary. The decision whether an item (file, picture, album) needs to be updated is done by comparing timestamps (mtime specifically). Due to that reason it's important to keep this fact in mind when replacing single image which carries older timestamp than other files. Either don't use the update mode or 'touch' that new file. Changes made to any XML file will result in whole album re-generation (excluding subalbums). --- src/cgg.c | 15 +++-- src/gallery-utils.c | 29 +++++++++ src/gallery-utils.h | 5 ++ src/generators.c | 165 ++++++++++++++++++++++++++++------------------------ src/generators.h | 11 ++-- src/job-manager.c | 96 ++++++++++++++++++------------ src/setup.h | 1 + 7 files changed, 200 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/cgg.c b/src/cgg.c index f5776b4..aa8a2ab 100644 --- a/src/cgg.c +++ b/src/cgg.c @@ -44,19 +44,21 @@ * parse_cmd: parse commandline and fill global variable parameters */ gboolean -parse_cmd (int argc, char* argv[], char **source_dir, char **dst_dir, gboolean *verbose, int *jobs) +parse_cmd (int argc, char* argv[], char **source_dir, char **dst_dir, gboolean *verbose, int *jobs, gboolean *update) { static gboolean _verbose = FALSE; static gchar *_source_dir = NULL; static gchar *_dst_dir = NULL; static int _jobs = 1; + static gboolean _update = FALSE; static GOptionEntry entries[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &_verbose, "Be verbose", NULL }, - { "source", 's', 0, G_OPTION_ARG_STRING, &_source_dir, "Specifies path to source structure", NULL }, + { "source", 's', 0, G_OPTION_ARG_STRING, &_source_dir, "Specifies a path to source structure", NULL }, { "output", 'o', 0, G_OPTION_ARG_STRING, &_dst_dir, "Generate files to the specified directory instead of current", NULL }, { "jobs", 'j', 0, G_OPTION_ARG_INT, &_jobs, "Allow N jobs at once (default=1)", NULL }, + { "update", 'u', 0, G_OPTION_ARG_NONE, &_update, "Update the output structure", NULL }, { NULL } }; @@ -73,7 +75,7 @@ parse_cmd (int argc, char* argv[], char **source_dir, char **dst_dir, gboolean * g_option_context_add_main_entries (context, entries, NULL); if (argc == 1) { - s1 = g_option_context_get_help (context, TRUE, NULL); + s1 = g_option_context_get_help (context, TRUE, NULL); g_print ("%s", s1); g_free (s1); g_option_context_free (context); @@ -82,7 +84,7 @@ parse_cmd (int argc, char* argv[], char **source_dir, char **dst_dir, gboolean * if (! g_option_context_parse (context, &argc, &argv, &error)) { g_print ("option parsing failed: %s\n", error->message); - s1 = g_option_context_get_help (context, TRUE, NULL); + s1 = g_option_context_get_help (context, TRUE, NULL); g_print ("%s", s1); g_free (s1); g_option_context_free (context); @@ -94,6 +96,7 @@ parse_cmd (int argc, char* argv[], char **source_dir, char **dst_dir, gboolean * *dst_dir = _dst_dir; *verbose = _verbose; *jobs = _jobs; + *update = _update; return TRUE; } @@ -106,6 +109,7 @@ main(int argc, char* argv[]) char *source_dir; char *dst_dir; gboolean verbose; + gboolean update; int jobs; TGallerySetup *setup; time_t time_start = time (NULL); @@ -130,7 +134,7 @@ main(int argc, char* argv[]) /* Parse commandline */ - if (! parse_cmd (argc, argv, &source_dir, &dst_dir, &verbose, &jobs)) + if (! parse_cmd (argc, argv, &source_dir, &dst_dir, &verbose, &jobs, &update)) return -1; if ((! source_dir) || (access (source_dir, R_OK))) { @@ -165,6 +169,7 @@ main(int argc, char* argv[]) /* Start building the gallery tree */ setup->verbose = verbose; + setup->update_mode = update; build_tree (setup, source_dir, dst_dir, NULL, -1, jobs); if (verbose) { diff --git a/src/gallery-utils.c b/src/gallery-utils.c index 8ec258a..29c456d 100644 --- a/src/gallery-utils.c +++ b/src/gallery-utils.c @@ -326,3 +326,32 @@ log_error (const gchar *format, ...) stats_errors_inc (); } + + +/* + * needs_update: returns TRUE if the destionation file needs updating, also when missing + */ +gboolean +needs_update (const char *source, const char *dest) +{ + struct stat src_stat; + struct stat dst_stat; + + memset (&src_stat, 0, sizeof (src_stat)); + memset (&dst_stat, 0, sizeof (dst_stat)); + + /* if we can't stat the source file, return FALSE to prevent further errors during update */ + if (stat (source, &src_stat) == -1) { + log_error ("needs_update: cannot stat source file \"%s\": %s\n", source, strerror (errno)); + return FALSE; + } + + /* if we can't stat the destination file, we need update anyway */ + if (stat (dest, &dst_stat) == -1) + return TRUE; + /* destination file size should not be zero */ + if (dst_stat.st_size <= 0) + return TRUE; + + return (src_stat.st_mtime > dst_stat.st_mtime); +} diff --git a/src/gallery-utils.h b/src/gallery-utils.h index d9c1d8a..85ad35d 100644 --- a/src/gallery-utils.h +++ b/src/gallery-utils.h @@ -73,6 +73,11 @@ const char *extract_file_ext (const char *filename); */ void log_error (const gchar *format, ...) G_GNUC_PRINTF (1, 2); +/* + * needs_update: returns TRUE if the destionation file needs updating, also when missing + */ +gboolean needs_update (const char *source, const char *dest); + #ifdef __cplusplus } diff --git a/src/generators.c b/src/generators.c index 0a21b7e..c094e32 100644 --- a/src/generators.c +++ b/src/generators.c @@ -38,12 +38,13 @@ /* * generate_image: generate needed image sizes */ -void +gboolean generate_image (TGallerySetup *setup, TAlbum *items, TIndexItem *item, unsigned int item_index, - const char *dst_dir) + const char *dst_dir, + gboolean update_when_necessary) { unsigned long new_w, new_h; unsigned long thumb_w, thumb_h; @@ -55,16 +56,18 @@ generate_image (TGallerySetup *setup, char *thumb_src_full; char *s1; int bigq; + gboolean res; item->gen_img_src = NULL; item->gen_thumb = NULL; thumb_src_full = NULL; img_src_full = NULL; + orig_dst = NULL; if (items->type == GALLERY_TYPE_INDEX) { if (item->thumbnail == NULL || strlen (item->thumbnail) == 0) - return; + return FALSE; img_src_full = g_strconcat (items->base_dir, "/", item->thumbnail, NULL); thumb_src_full = g_strconcat (items->base_dir, "/", item->thumbnail, NULL); item->gen_img_src = g_path_get_basename (item->thumbnail); @@ -84,89 +87,99 @@ generate_image (TGallerySetup *setup, g_free (s1); } - get_image_sizes (img_src_full, &new_w, &new_h); - - if ((new_w > 0) && (new_h > 0)) { - stats_images_inc (); - item->gen_portrait = (new_w / new_h) < 1; - - /* Generate thumbnail */ - g_assert (thumb_src_full != NULL); - get_image_sizes (thumb_src_full, &thumb_w, &thumb_h); - thumb_dst = g_strconcat (dst_dir, "/", setup->thumbnail_dir, "/", item->gen_thumb, NULL); - - if ((thumb_w > 0) && (thumb_h > 0)) { - if (! item->gen_portrait) - calculate_sizes (setup->thumbnail_landscape_width, setup->thumbnail_landscape_height, &thumb_w, &thumb_h); - else - calculate_sizes (setup->thumbnail_portrait_width, setup->thumbnail_portrait_height, &thumb_w, &thumb_h); - if (! resize_image (thumb_src_full, thumb_dst, thumb_w, thumb_h, setup->thumbnail_quality, TRUE)) - log_error ("generate_image: error resizing thumbnail %s\n", thumb_src_full); - else - g_free (thumb_dst); - } else - log_error ("generate_image: thumbnail %s sizes are %lux%lu\n", thumb_src_full, thumb_w, thumb_h); - - - /* Generate/copy preview and original image */ - if (items->type == GALLERY_TYPE_ALBUM) - { - big_dst = g_strconcat (dst_dir, "/", setup->img_big_dir, "/", item->gen_img_src, NULL); - if (item->preview == NULL) { - /* No preview image supplied, generate it from original */ - bigq = setup->preview_quality; - if ((items->quality > 0) && (items->quality <= 100)) - bigq = items->quality; - if ((item->quality > 0) && (item->quality <= 100)) - bigq = item->quality; - - if ((item->width > 0) && (item->height > 0)) { - calculate_sizes (item->width, item->height, &new_w, &new_h); - } else { - if (! item->gen_portrait) - { - if ((items->landscape_width > 0) && (items->landscape_height > 0)) - calculate_sizes (items->landscape_width, items->landscape_height, &new_w, &new_h); - else - calculate_sizes (setup->preview_landscape_width, setup->preview_landscape_height, &new_w, &new_h); - } - else - { - if ((items->portrait_width > 0) && (items->portrait_height > 0)) - calculate_sizes (items->portrait_width, items->portrait_height, &new_w, &new_h); + /* Make paths */ + thumb_dst = g_strconcat (dst_dir, "/", setup->thumbnail_dir, "/", item->gen_thumb, NULL); + big_dst = g_strconcat (dst_dir, "/", setup->img_big_dir, "/", item->gen_img_src, NULL); + if (item->force_fullsize || (items->fullsize && ! item->force_nofullsize) || + (! item->force_nofullsize && ! items->nofullsize && ! setup->nofullsize)) + orig_dst = g_strconcat (dst_dir, "/", setup->img_orig_dir, "/", item->gen_img_src, NULL); + res = (! update_when_necessary) || needs_update (thumb_src_full, thumb_dst) || + (items->type == GALLERY_TYPE_ALBUM && (needs_update (img_src_full, big_dst) || (orig_dst && needs_update (img_src_full, orig_dst)))); + + /* Do something when necessary */ + if (res) { + get_image_sizes (img_src_full, &new_w, &new_h); + + if ((new_w > 0) && (new_h > 0)) { + stats_images_inc (); + item->gen_portrait = (new_w / new_h) < 1; + + /* Generate thumbnail */ + g_assert (thumb_src_full != NULL); + get_image_sizes (thumb_src_full, &thumb_w, &thumb_h); + + if ((thumb_w > 0) && (thumb_h > 0)) { + if (! item->gen_portrait) + calculate_sizes (setup->thumbnail_landscape_width, setup->thumbnail_landscape_height, &thumb_w, &thumb_h); + else + calculate_sizes (setup->thumbnail_portrait_width, setup->thumbnail_portrait_height, &thumb_w, &thumb_h); + if (! resize_image (thumb_src_full, thumb_dst, thumb_w, thumb_h, setup->thumbnail_quality, TRUE)) + log_error ("generate_image: error resizing thumbnail %s\n", thumb_src_full); + } else + log_error ("generate_image: thumbnail %s sizes are %lux%lu\n", thumb_src_full, thumb_w, thumb_h); + + + /* Generate/copy preview image */ + if (items->type == GALLERY_TYPE_ALBUM) { + if (item->preview == NULL) { + /* No preview image supplied, generate it from original */ + bigq = setup->preview_quality; + if ((items->quality > 0) && (items->quality <= 100)) + bigq = items->quality; + if ((item->quality > 0) && (item->quality <= 100)) + bigq = item->quality; + + if ((item->width > 0) && (item->height > 0)) { + calculate_sizes (item->width, item->height, &new_w, &new_h); + } else { + if (! item->gen_portrait) + { + if ((items->landscape_width > 0) && (items->landscape_height > 0)) + calculate_sizes (items->landscape_width, items->landscape_height, &new_w, &new_h); + else + calculate_sizes (setup->preview_landscape_width, setup->preview_landscape_height, &new_w, &new_h); + } else - calculate_sizes (setup->preview_portrait_width, setup->preview_portrait_height, &new_w, &new_h); + { + if ((items->portrait_width > 0) && (items->portrait_height > 0)) + calculate_sizes (items->portrait_width, items->portrait_height, &new_w, &new_h); + else + calculate_sizes (setup->preview_portrait_width, setup->preview_portrait_height, &new_w, &new_h); + } } + + g_assert (img_src_full != NULL); + if (! resize_image (img_src_full, big_dst, new_w, new_h, bigq, FALSE)) + log_error ("generate_image: error resizing big image %s\n", img_src_full); + } + else + { + /* Copy the preview (big) image provided */ + big_src = g_strconcat (items->base_dir, "/", item->preview, NULL); + if (! copy_file (big_src, big_dst)) + log_error ("generate_image: error copying preview image %s\n", big_src); + g_free (big_src); } + modify_exif (big_dst, setup->erase_exif_thumbnail, setup->add_copyright); - g_assert (img_src_full != NULL); - if (! resize_image (img_src_full, big_dst, new_w, new_h, bigq, FALSE)) - log_error ("generate_image: error resizing big image %s\n", img_src_full); - } - else - { - /* Copy the preview (big) image provided */ - big_src = g_strconcat (items->base_dir, "/", item->preview, NULL); - if (! copy_file (big_src, big_dst)) - log_error ("generate_image: error copying preview image %s\n", big_src); - g_free (big_src); - } - modify_exif (big_dst, setup->erase_exif_thumbnail, setup->add_copyright); - g_free (big_dst); - if (item->force_fullsize || (items->fullsize && ! item->force_nofullsize) || - (! item->force_nofullsize && ! items->nofullsize && ! setup->nofullsize)) - { - orig_dst = g_strconcat (dst_dir, "/", setup->img_orig_dir, "/", item->gen_img_src, NULL); - if (! copy_file(img_src_full, orig_dst)) - log_error ("generate_image: error copying original image %s\n", img_src_full); - modify_exif (orig_dst, setup->erase_exif_thumbnail, setup->add_copyright); - g_free (orig_dst); + /* Generate/copy original image */ + if (orig_dst) { + if (! copy_file (img_src_full, orig_dst)) + log_error ("generate_image: error copying original image %s\n", img_src_full); + else + modify_exif (orig_dst, setup->erase_exif_thumbnail, setup->add_copyright); + } } } } g_free (img_src_full); g_free (thumb_src_full); + g_free (big_dst); + g_free (thumb_dst); + g_free (orig_dst); + + return res; } diff --git a/src/generators.h b/src/generators.h index 584cff3..31636f0 100644 --- a/src/generators.h +++ b/src/generators.h @@ -23,11 +23,12 @@ /* * generate_image: generate needed image sizes */ -void generate_image (TGallerySetup *setup, - TAlbum *items, - TIndexItem *item, - unsigned int item_index, - const char *dst_dir); +gboolean generate_image (TGallerySetup *setup, + TAlbum *items, + TIndexItem *item, + unsigned int item_index, + const char *dst_dir, + gboolean update_when_necessary); /* * write_html_album: process album and index template files diff --git a/src/job-manager.c b/src/job-manager.c index 8344e60..1f37595 100644 --- a/src/job-manager.c +++ b/src/job-manager.c @@ -41,6 +41,7 @@ typedef struct { TGallerySetup *setup; TAlbum *items; const char *dst_dir; + gboolean force_update; } TJob; @@ -51,10 +52,10 @@ mirror_files (TGallerySetup *setup, char **files, const char *src_tree, const ch { char **extra; char *s1, *s2, *s3; + int processed = 0; if (files && g_strv_length (files) > 0) { extra = files; - if (setup->verbose) printf ("%s", label); while (*extra) { s1 = g_strstrip (*extra); if (strlen (s1) > 0) { @@ -70,16 +71,24 @@ mirror_files (TGallerySetup *setup, char **files, const char *src_tree, const ch g_free (s3); /* Copy the file */ - if (setup->verbose) printf (" %s", s1); s2 = g_strconcat (src_tree, "/", s1, NULL); s3 = g_strconcat (dst_dir, "/", s1, NULL); - copy_file (s2, s3); + if (! setup->update_mode || needs_update (s2, s3)) { + if (setup->verbose) { + if (processed == 0) + printf ("%s", label); + printf (" %s", s1); + } + copy_file (s2, s3); + processed++; + } g_free (s2); g_free (s3); } extra++; } - if (setup->verbose) printf ("\n"); + if (setup->verbose && processed > 0) + printf ("\n"); } } @@ -99,6 +108,7 @@ thread_func (gpointer data) char *s1, *s2, *s3; int total, index, real_index; TJob *job = data; + gboolean updated; do { item = NULL; @@ -129,13 +139,16 @@ thread_func (gpointer data) /* actually do some work */ if (item != NULL) { imgname = g_path_get_basename ((item->path == NULL && item->preview) ? item->preview : item->path); - G_LOCK (items_print); - if (job->setup->verbose) - g_print (" [%d/%d] Processing item \"%s\"\n", index, total, imgname); - G_UNLOCK (items_print); + updated = generate_image (job->setup, job->items, item, real_index, job->dst_dir, ! job->force_update); + + if (updated) { + G_LOCK (items_print); + if (job->setup->verbose) + g_print (" [%d/%d] Processing item \"%s\"\n", index, total, imgname); + G_UNLOCK (items_print); + } - generate_image (job->setup, job->items, item, real_index, job->dst_dir); - if (job->items->type == GALLERY_TYPE_ALBUM) { + if (updated && job->items->type == GALLERY_TYPE_ALBUM) { s1 = g_strconcat (job->setup->real_templates_dir, "/", job->setup->template_photo, NULL); s2 = g_strconcat (job->items->base_dir, "/", (item->path == NULL && item->preview) ? item->preview : item->path, NULL); s3 = g_strconcat (job->dst_dir, "/", imgname, GET_EXT (job->setup->index_file_name), NULL); @@ -181,12 +194,14 @@ build_tree (TGallerySetup *setup, char *img_big_dir; char *img_orig_dir; char *template; + char *dst_album_file; gboolean res; int i; TJob *job; GError *error; GThread *thread; GList *thread_list; + gboolean force_update; printf ("Processing directory \"%s\"\n", src_tree); stats_dirs_inc (); @@ -223,10 +238,14 @@ build_tree (TGallerySetup *setup, free_album_data (items); return FALSE; } - g_free (idx_file); items->parent_index = parent_index; items->parent_item_index = parent_item_index; + /* Check if update is necessary */ + dst_album_file = g_strconcat (dst_dir, "/", setup->index_file_name, NULL); + force_update = (! setup->update_mode || needs_update (idx_file, dst_album_file)); + g_free (idx_file); + /* Copy support files */ if (! setup->support_files_use_common_root || parent_index == NULL) { /* copy only if we're in root level or old-style is active */ @@ -234,11 +253,13 @@ build_tree (TGallerySetup *setup, /* favicon */ if (setup->favicon_file && strlen (setup->favicon_file) > 0) { - if (setup->verbose) printf (" Copying favicon: %s\n", setup->favicon_file); s3 = g_path_get_dirname (setup->setup_xml_path); s1 = g_strconcat (s3, "/", setup->favicon_file, NULL); s2 = g_strconcat (dst_dir, "/", setup->favicon_file, NULL); - copy_file (s1, s2); + if (! setup->update_mode || needs_update (s1, s2)) { + if (setup->verbose) printf (" Copying favicon: %s\n", setup->favicon_file); + copy_file (s1, s2); + } g_free (s1); g_free (s2); g_free (s3); @@ -251,6 +272,7 @@ build_tree (TGallerySetup *setup, if (g_mkdir_with_parents (thumb_dir, DEFAULT_DATA_DIR_MODE)) { log_error ("error making target thumbnail directory: %s\n", strerror (errno)); g_free (thumb_dir); + g_free (dst_album_file); free_album_data (items); return FALSE; } @@ -275,6 +297,7 @@ build_tree (TGallerySetup *setup, g_free (img_big_dir); g_free (img_orig_dir); if (! res) { + g_free (dst_album_file); free_album_data (items); return FALSE; } @@ -285,6 +308,7 @@ build_tree (TGallerySetup *setup, job->items = items; job->setup = setup; job->dst_dir = dst_dir; + job->force_update = force_update; #ifdef G_THREADS_ENABLED thread_list = NULL; @@ -315,33 +339,33 @@ build_tree (TGallerySetup *setup, g_free (job); - /* Start generating items */ - if (items->type == GALLERY_TYPE_INDEX) - template = g_strconcat ("/", setup->template_index, NULL); - else - if (items->type == GALLERY_TYPE_ALBUM) - template = g_strconcat ("/", setup->template_album, NULL); - else - /* default to album */ - template = g_strconcat ("/", setup->template_album, NULL); - - if (setup->verbose) printf (" Writing %s\n", setup->index_file_name); - s1 = g_strconcat (setup->real_templates_dir, template, NULL); - s2 = g_strconcat (dst_dir, "/", setup->index_file_name, NULL); - res = write_html_album (setup, s1, s2, items); - g_free (s1); - g_free (s2); - g_free (template); - if (! res) { - log_error ("error generating target index file\n"); - free_album_data (items); - return FALSE; + /* Generate album page */ + if (force_update) { + if (items->type == GALLERY_TYPE_INDEX) + template = g_strconcat ("/", setup->template_index, NULL); + else + if (items->type == GALLERY_TYPE_ALBUM) + template = g_strconcat ("/", setup->template_album, NULL); + else + /* default to album */ + template = g_strconcat ("/", setup->template_album, NULL); + + if (setup->verbose) printf (" Writing %s\n", setup->index_file_name); + s1 = g_strconcat (setup->real_templates_dir, template, NULL); + res = write_html_album (setup, s1, dst_album_file, items); + g_free (s1); + g_free (template); + if (! res) { + log_error ("error generating target index file\n"); + free_album_data (items); + return FALSE; + } } + g_free (dst_album_file); /* Recurse to sub-albums (in case of album index) */ - if (items->type == GALLERY_TYPE_INDEX) - { + if (items->type == GALLERY_TYPE_INDEX) { if (items->items->len > 0) { for (i = 0; i < items->items->len; i++) { item = g_ptr_array_index (items->items, i); diff --git a/src/setup.h b/src/setup.h index 4cd2629..2356620 100644 --- a/src/setup.h +++ b/src/setup.h @@ -35,6 +35,7 @@ /* Global gallery setup */ typedef struct { gboolean verbose; + gboolean update_mode; char *real_templates_dir; char *setup_xml_path; -- cgit v1.2.3