From 6f0cf4521b2f2613f0a41b133f1950d3c51b7b7f Mon Sep 17 00:00:00 2001 From: Kylian Schmidt Date: Thu, 23 Apr 2026 13:09:26 +0200 Subject: [PATCH] Add support for incremental updates in gallery generation - Introduced `source_to_update` parameter to selectively regenerate specific sources. - Updated documentation to reflect new behavior for `clean_first` and `source_to_update`. - Modified CLI and legacy CLI to handle source overrides appropriately. --- gallery/api.py | 35 +++++++++++++++++++++++++++++++++-- gallery/cli.py | 16 ++++++++++------ generate_gallery.py | 14 +++++++++----- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/gallery/api.py b/gallery/api.py index 7579a3f..62079cb 100644 --- a/gallery/api.py +++ b/gallery/api.py @@ -18,6 +18,7 @@ def generate( sources: List[Union[GallerySource, Dict[str, Any]]] = None, clean_first: bool = False, verbose: bool = False, + source_to_update: GallerySource = None, ) -> bool: """ Generate a scientific gallery from plot sources. @@ -33,8 +34,13 @@ def generate( Required if config is not provided. sources: List of GallerySource objects or dicts. Required if config is not provided. - clean_first: If True, removes and recreates the gallery directory - verbose: If True, prints progress messages + clean_first: If True, removes and recreates the gallery directory. + If False (default), performs incremental update. + verbose: If True, prints progress messages. + source_to_update: Optional specific source to update. When provided, + only this source is regenerated (incremental mode). + Other sources in config are preserved in the index. + Only effective when clean_first is False. Returns: True if gallery generation was successful, False otherwise @@ -116,6 +122,23 @@ def generate( if verbose: print(f"Warning: Could not clean directory: {e}") return False + elif source_to_update and gallery_root.exists(): + # Incremental mode: only clean the specific source subdirectory + source_subdir = gallery_root / source_to_update.name + if source_subdir.exists(): + if verbose: + print( + f"Updating source directory {source_to_update.name}..." + ) + try: + shutil.rmtree(source_subdir) + except Exception as e: + if verbose: + print( + f"Warning: Could not clean source subdirectory " + f"{source_subdir}: {e}" + ) + return False try: gallery_root.mkdir(parents=True, exist_ok=True) @@ -141,6 +164,14 @@ def generate( # Process sources source_subdirs = [] for source in config.sources: + # Skip sources not matching the update target (if specified) + if source_to_update and source.name != source_to_update.name: + # Still include them in the index if they exist + source_web_dir = gallery_root / source.name + if source_web_dir.exists(): + source_subdirs.append(source.name) + continue + try: source_path = Path(source.path).resolve() diff --git a/gallery/cli.py b/gallery/cli.py index 8befca7..c3bfcec 100644 --- a/gallery/cli.py +++ b/gallery/cli.py @@ -68,7 +68,9 @@ Examples: config = GalleryConfig.from_yaml(args.config) # Handle source override + source_to_update = None if args.source: + from gallery.config import GallerySource source_path = Path(args.source).resolve() # Check if source is in config @@ -80,24 +82,26 @@ Examples: # If not in config, create a temporary source entry if matching_source is None: - from gallery.config import GallerySource source_name = source_path.name - config.sources = [ - GallerySource(name=source_name, path=source_path) - ] + source_to_update = GallerySource( + name=source_name, + path=source_path + ) + config.sources.append(source_to_update) if args.verbose: print( f"Source {args.source} not in config. " f"Adding temporarily as '{source_name}'" ) else: - config.sources = [matching_source] + source_to_update = matching_source # Generate gallery success = generate( config=config, clean_first=args.clean, - verbose=args.verbose + verbose=args.verbose, + source_to_update=source_to_update ) sys.exit(0 if success else 1) diff --git a/generate_gallery.py b/generate_gallery.py index 6045591..f583f79 100644 --- a/generate_gallery.py +++ b/generate_gallery.py @@ -35,6 +35,7 @@ def main(clean_first: bool = False, source_override: str = None) -> None: config = GalleryConfig.from_yaml("config.yaml") # Handle source override + source_to_update = None if source_override: from pathlib import Path from gallery.config import GallerySource @@ -51,21 +52,24 @@ def main(clean_first: bool = False, source_override: str = None) -> None: # If not in config, create a temporary source entry if matching_source is None: source_name = source_path.name + source_to_update = GallerySource( + name=source_name, + path=source_path + ) + config.sources.append(source_to_update) print( f"Source {source_override} not in config. " f"Adding temporarily as '{source_name}'" ) - config.sources = [ - GallerySource(name=source_name, path=source_path) - ] else: - config.sources = [matching_source] + source_to_update = matching_source # Generate gallery using the new API success = generate( config=config, clean_first=clean_first, - verbose=True + verbose=True, + source_to_update=source_to_update ) if not success: