Skip to content

Commit 5c2c96c

Browse files
committed
Add option to output digest to stdout
This change introduces the ability for users to direct the output of the gitingest tool to standard output (stdout) instead of writing to a file. This is useful for piping the output to other commands or viewing it directly in the terminal.
1 parent bf5d760 commit 5c2c96c

File tree

4 files changed

+54
-13
lines changed

4 files changed

+54
-13
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,20 @@ Issues and feature requests are welcome to the repo.
7777
The `gitingest` command line tool allows you to analyze codebases and create a text dump of their contents.
7878

7979
```bash
80-
# Basic usage
80+
# Basic usage (writes to digest.txt by default)
8181
gitingest /path/to/directory
8282

8383
# From URL
8484
gitingest https://github.com/cyclotruc/gitingest
8585

86+
# Output to STDOUT instead of a file
87+
gitingest . -o -
88+
8689
# See more options
8790
gitingest --help
8891
```
8992

90-
This will write the digest in a text file (default `digest.txt`) in your current working directory.
93+
By default, the digest is written to a text file (`digest.txt`) in your current working directory. Use `-o -` or `--output -` to print to standard output instead.
9194

9295
## 🐍 Python package usage
9396

src/gitingest/cli.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def main(
3737
The source directory or repository to analyze.
3838
output : str, optional
3939
The path where the output file will be written. If not specified, the output will be written
40-
to a file named `<repo_name>.txt` in the current directory.
40+
to a file named `<repo_name>.txt` in the current directory. Use '-' to output to stdout.
4141
max_size : int
4242
The maximum file size to process, in bytes. Files larger than this size will be ignored.
4343
exclude_pattern : Tuple[str, ...]
@@ -63,15 +63,16 @@ async def _async_main(
6363
Analyze a directory or repository and create a text dump of its contents.
6464
6565
This command analyzes the contents of a specified source directory or repository, applies custom include and
66-
exclude patterns, and generates a text summary of the analysis which is then written to an output file.
66+
exclude patterns, and generates a text summary of the analysis which is then written to an output file
67+
or printed to stdout.
6768
6869
Parameters
6970
----------
7071
source : str
7172
The source directory or repository to analyze.
7273
output : str, optional
7374
The path where the output file will be written. If not specified, the output will be written
74-
to a file named `<repo_name>.txt` in the current directory.
75+
to a file named `<repo_name>.txt` in the current directory. Use '-' to output to stdout.
7576
max_size : int
7677
The maximum file size to process, in bytes. Files larger than this size will be ignored.
7778
exclude_pattern : Tuple[str, ...]
@@ -91,16 +92,33 @@ async def _async_main(
9192
exclude_patterns = set(exclude_pattern)
9293
include_patterns = set(include_pattern)
9394

94-
if not output:
95-
output = OUTPUT_FILE_NAME
96-
summary, _, _ = await ingest_async(source, max_size, include_patterns, exclude_patterns, branch, output=output)
95+
output_target = output
96+
if output is None:
97+
output_target = OUTPUT_FILE_NAME
98+
click.echo(f"Analyzing source, output will be written to '{output_target}'...", err=True)
99+
elif output == "-":
100+
click.echo("Analyzing source, preparing output for stdout...", err=True)
101+
else:
102+
click.echo(f"Analyzing source, output will be written to '{output_target}'...", err=True)
103+
104+
105+
summary, _, _ = await ingest_async(
106+
source, max_size, include_patterns, exclude_patterns, branch, output=output_target
107+
)
108+
109+
if output != "-":
110+
click.echo(f"Analysis complete! Output written to: {output_target}")
111+
click.echo("\nSummary:")
112+
click.echo(summary)
113+
else:
114+
click.echo("\n--- Summary ---", err=True)
115+
click.echo(summary, err=True)
116+
click.echo("--- End Summary ---", err=True)
117+
click.echo("Analysis complete! Output sent to stdout.", err=True)
97118

98-
click.echo(f"Analysis complete! Output written to: {output}")
99-
click.echo("\nSummary:")
100-
click.echo(summary)
101119

102120
except Exception as exc:
103-
click.echo(f"Error: {exc}", err=True)
121+
click.echo(f"Error processing '{source}': {exc}", err=True)
104122
raise click.Abort()
105123

106124

src/gitingest/entrypoint.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import inspect
55
import shutil
6+
import sys
67
from typing import Optional, Set, Tuple, Union
78

89
from gitingest.cloning import clone_repo
@@ -85,7 +86,12 @@ async def ingest_async(
8586

8687
summary, tree, content = ingest_query(query)
8788

88-
if output is not None:
89+
if output == "-":
90+
loop = asyncio.get_running_loop()
91+
output_data = tree + "\n" + content
92+
await loop.run_in_executor(None, sys.stdout.write, output_data)
93+
await loop.run_in_executor(None, sys.stdout.flush)
94+
elif output is not None:
8995
with open(output, "w", encoding="utf-8") as f:
9096
f.write(tree + "\n" + content)
9197

tests/test_cli.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,17 @@ def test_cli_with_options():
3939
assert os.path.exists(OUTPUT_FILE_NAME), f"Output file was not created at {OUTPUT_FILE_NAME}"
4040

4141
os.remove(OUTPUT_FILE_NAME)
42+
43+
44+
def test_cli_with_stdout_output():
45+
"""Test CLI invocation with output directed to STDOUT."""
46+
runner = CliRunner(mix_stderr=False)
47+
result = runner.invoke(main, ["./", "--output", "-", "--exclude-pattern", "tests/"])
48+
49+
assert result.exit_code == 0, f"CLI exited with code {result.exit_code}, stderr: {result.stderr}"
50+
assert "---" in result.output, "Expected file separator '---' not found in STDOUT"
51+
assert "src/gitingest/cli.py" in result.output, "Expected content (e.g., src/gitingest/cli.py) not found in STDOUT"
52+
assert not os.path.exists(OUTPUT_FILE_NAME), f"Output file {OUTPUT_FILE_NAME} was unexpectedly created."
53+
assert f"Analysis complete! Output sent to stdout." not in result.output
54+
assert "Analysis complete!" in result.stderr, "Expected summary message 'Analysis complete!' not found in STDERR"
55+
assert f"Output written to: {OUTPUT_FILE_NAME}" not in result.stderr

0 commit comments

Comments
 (0)