1010from dataclasses import dataclass
1111from functools import lru_cache
1212from pathlib import Path
13+ from typing import TYPE_CHECKING
1314
1415import typer
1516from invoke import Context , UnexpectedExit , task
1819from slugify import slugify
1920from tqdm import tqdm
2021
22+ if TYPE_CHECKING :
23+ from collections .abc import Generator
24+
2125from conjuring .colors import Color
2226from conjuring .constants import REGEX_JIRA_TICKET_TITLE
2327from conjuring .grimoire import (
@@ -440,9 +444,17 @@ def new_branch(c: Context, title: str) -> None:
440444 c .run (f"git checkout -b { branch_name } " )
441445
442446
443- def _find_git_repositories (c : Context , search_dirs : list [Path ]) -> set [Path ]:
444- """Find all Git repositories in the given directories using fd."""
445- git_repos = set ()
447+ def _find_git_repositories_streaming (c : Context , search_dirs : list [Path ]) -> Generator [Path , None , None ]:
448+ """Find Git repositories and yield them as they're discovered.
449+
450+ This streaming version allows processing to start immediately without waiting
451+ for all repositories to be found first.
452+
453+ Yields:
454+ Path: Repository path as it's discovered
455+
456+ """
457+ seen_repos = set ()
446458 for search_dir in search_dirs :
447459 if not search_dir .exists ():
448460 print_warning (f"Directory does not exist: { search_dir } " )
@@ -454,13 +466,13 @@ def _find_git_repositories(c: Context, search_dirs: list[Path]) -> set[Path]:
454466 lines = run_lines (c , rf"fd -H -t d --no-ignore-vcs '^\.git$' '{ search_dir } '" , dry = False )
455467 for line in lines :
456468 repo_path = Path (line ).parent
457- git_repos .add (repo_path )
469+ if repo_path not in seen_repos :
470+ seen_repos .add (repo_path )
471+ yield repo_path
458472 except Exception as e : # noqa: BLE001
459473 print_warning (f"Error searching for Git repos in { search_dir } : { e } " )
460474 continue
461475
462- return git_repos
463-
464476
465477def is_valid_git_repository (repo_path : Path ) -> bool :
466478 """Check if the given path is a valid Git repository."""
@@ -589,24 +601,25 @@ def dirty(c: Context, dir_: list[str | Path]) -> bool:
589601 # Convert to Path objects and expand user paths
590602 search_dirs = [Path (d ).expanduser ().resolve () for d in dir_ ]
591603
592- # Find all Git repositories using fd
593- git_repos = _find_git_repositories (c , search_dirs )
594-
595- if not git_repos :
596- print_warning ("No Git repositories found" )
597- return False
598-
599- # Check each repository for dirty status and collect data
604+ # Collect repositories as they're found and check them immediately
600605 dirty_repos_data = []
601- sorted_repos = sorted (git_repos )
602- with tqdm (total = len (sorted_repos ), desc = "Checking repositories" , unit = "repo" ) as pbar :
603- for repo_path in sorted_repos :
606+ all_repos = []
607+
608+ # Use streaming approach: process repos as they're discovered
609+ # This makes the progress bar appear immediately
610+ with tqdm (desc = "Finding dirty repositories" , unit = " repos" ) as pbar :
611+ for repo_path in _find_git_repositories_streaming (c , search_dirs ):
612+ all_repos .append (repo_path )
604613 pbar .set_postfix_str (str (repo_path ))
605614 repo_data = _is_repo_dirty (c , repo_path )
606615 if repo_data :
607616 dirty_repos_data .append (repo_data )
608617 pbar .update (1 )
609618
619+ if not all_repos :
620+ print_warning ("No Git repositories found" )
621+ return False
622+
610623 if not dirty_repos_data :
611624 print_warning ("No dirty repositories found" )
612625 return False
0 commit comments