From f71d28deec07e534cecb0dccdf2d96745be72251 Mon Sep 17 00:00:00 2001 From: Jonathan Carroll Otsuka Date: Sat, 4 Jan 2025 18:30:51 -0600 Subject: [PATCH 1/2] Adding the option `--repos-without-matches` This will return all repositories not containing a match. It is the inverse of what `--repos-with-matches` returns. --- all_repos/cli.py | 7 +++++++ all_repos/find_files.py | 1 + all_repos/grep.py | 19 +++++++++++++++++++ tests/grep_test.py | 42 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/all_repos/cli.py b/all_repos/cli.py index 8591c6c..2f8cc0f 100644 --- a/all_repos/cli.py +++ b/all_repos/cli.py @@ -61,6 +61,13 @@ def add_repos_with_matches_arg(parser: ParserType) -> None: ) +def add_repos_without_matches_arg(parser: ParserType) -> None: + parser.add_argument( + '--repos-without-matches', action='store_true', + help='only print repositories without matches.', + ) + + def add_output_paths_arg(parser: ParserType) -> None: parser.add_argument( '--output-paths', action='store_true', diff --git a/all_repos/find_files.py b/all_repos/find_files.py index b9740fa..6e3519a 100644 --- a/all_repos/find_files.py +++ b/all_repos/find_files.py @@ -74,6 +74,7 @@ def main(argv: Sequence[str] | None = None) -> int: ) cli.add_common_args(parser) cli.add_repos_with_matches_arg(parser) + cli.add_repos_without_matches_arg(parser) cli.add_output_paths_arg(parser) parser.add_argument('pattern', help='the python regex to match.') args = parser.parse_args(argv) diff --git a/all_repos/grep.py b/all_repos/grep.py index 833e852..21454e0 100644 --- a/all_repos/grep.py +++ b/all_repos/grep.py @@ -43,6 +43,12 @@ def grep(config: Config, grep_args: Sequence[str]) -> dict[str, bytes]: def repos_matching(config: Config, grep_args: Sequence[str]) -> set[str]: return set(grep(config, ('--quiet', *grep_args))) +def repos_not_matching(config: Config, grep_args: Sequence[str]) -> set[str]: + grep_ret = set(grep(config, ('--quiet', *grep_args))) + repos = [os.path.join(config.output_dir, repo) for repo in config.get_cloned_repos()] + + return set(repos).difference(grep_ret) + def repos_matching_cli(config: Config, grep_args: Sequence[str]) -> int: try: @@ -54,6 +60,16 @@ def repos_matching_cli(config: Config, grep_args: Sequence[str]) -> int: return int(not matching) +def repos_not_matching_cli(config: Config, grep_args: Sequence[str]) -> int: + try: + not_matching = repos_not_matching(config, grep_args) + except GrepError as e: + return e.args[0] + for repo in sorted(not_matching): + print(repo) + return int(not not_matching) + + def grep_cli( config: Config, grep_args: Sequence[str], @@ -92,12 +108,15 @@ def main(argv: Sequence[str] | None = None) -> int: ) cli.add_common_args(parser) cli.add_repos_with_matches_arg(parser) + cli.add_repos_without_matches_arg(parser) cli.add_output_paths_arg(parser) args, rest = parser.parse_known_args(argv) config = load_config(args.config_filename) if args.repos_with_matches: return repos_matching_cli(config, rest) + elif args.repos_without_matches: + return repos_not_matching_cli(config, rest) else: return grep_cli( config, rest, output_paths=args.output_paths, use_color=args.color, diff --git a/tests/grep_test.py b/tests/grep_test.py index 11acd1d..1384271 100644 --- a/tests/grep_test.py +++ b/tests/grep_test.py @@ -8,7 +8,7 @@ from all_repos.config import load_config from all_repos.grep import grep from all_repos.grep import main -from all_repos.grep import repos_matching +from all_repos.grep import repos_matching, repos_not_matching def test_repos_matching(file_config_files): @@ -50,6 +50,46 @@ def test_repos_matching_cli(file_config_files, capsys): assert out == '' +def test_repos_not_matching(file_config_files): + config = load_config(file_config_files.cfg) + ret = repos_not_matching(config, ['^OH']) + assert ret == set() + ret = repos_not_matching(config, ['^OHAI']) + assert ret == {file_config_files.output_dir.join('repo2')} + ret = repos_not_matching(config, ['nope']) + assert ret == { + file_config_files.output_dir.join('repo1'), + file_config_files.output_dir.join('repo2'), + } + + +def test_repos_not_matching_cli(file_config_files, capsys): + ret = main(( + '-C', str(file_config_files.cfg), '--repos-without-matches', '^OH', + )) + assert ret == 1 + out, _ = capsys.readouterr() + assert out == '' + + + ret = main(( + '-C', str(file_config_files.cfg), '--repos-without-matches', 'OHAI', + )) + assert ret == 0 + out, _ = capsys.readouterr() + assert out == '{}\n'.format(file_config_files.output_dir.join('repo2')) + + ret = main(( + '-C', str(file_config_files.cfg), '--repos-without-matches', 'nope', + )) + assert ret == 0 + out, _ = capsys.readouterr() + assert out == '{}\n{}\n'.format( + file_config_files.output_dir.join('repo1'), + file_config_files.output_dir.join('repo2'), + ) + + def test_grep(file_config_files): config = load_config(file_config_files.cfg) ret = grep(config, ['^OH']) From 8a288c53f6f6547e866dc3df1e460e904e39b8cb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 00:42:12 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- all_repos/grep.py | 1 + tests/grep_test.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/all_repos/grep.py b/all_repos/grep.py index 21454e0..6b1aeae 100644 --- a/all_repos/grep.py +++ b/all_repos/grep.py @@ -43,6 +43,7 @@ def grep(config: Config, grep_args: Sequence[str]) -> dict[str, bytes]: def repos_matching(config: Config, grep_args: Sequence[str]) -> set[str]: return set(grep(config, ('--quiet', *grep_args))) + def repos_not_matching(config: Config, grep_args: Sequence[str]) -> set[str]: grep_ret = set(grep(config, ('--quiet', *grep_args))) repos = [os.path.join(config.output_dir, repo) for repo in config.get_cloned_repos()] diff --git a/tests/grep_test.py b/tests/grep_test.py index 1384271..f884008 100644 --- a/tests/grep_test.py +++ b/tests/grep_test.py @@ -8,7 +8,8 @@ from all_repos.config import load_config from all_repos.grep import grep from all_repos.grep import main -from all_repos.grep import repos_matching, repos_not_matching +from all_repos.grep import repos_matching +from all_repos.grep import repos_not_matching def test_repos_matching(file_config_files): @@ -71,7 +72,6 @@ def test_repos_not_matching_cli(file_config_files, capsys): out, _ = capsys.readouterr() assert out == '' - ret = main(( '-C', str(file_config_files.cfg), '--repos-without-matches', 'OHAI', ))