Add pipe output feature to repo-to-text

Fixes #9

Add support for output via pipe `repo-to-text > myfile.txt`.

* Modify `save_repo_to_text` function in `repo_to_text/main.py` to write to stdout if `--stdout` is specified.
* Add `--stdout` argument to `argparse` in `repo_to_text/main.py`.
* Update `main` function in `repo_to_text/main.py` to handle the new `--stdout` argument.
* Update `README.md` to include instructions for using the new pipe output feature.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/kirill-markin/repo-to-text/issues/9?shareId=XXXX-XXXX-XXXX-XXXX).
This commit is contained in:
Aleksey Bykhun 2024-10-30 04:49:57 -07:00
parent ad36a75a7a
commit d3998786c0
2 changed files with 55 additions and 41 deletions

View file

@ -76,6 +76,14 @@ You can customize the behavior of `repo-to-text` with the following options:
repo-to-text --debug > debug_log.txt 2>&1 repo-to-text --debug > debug_log.txt 2>&1
``` ```
- `--stdout`: Output the generated text to stdout instead of a file. This is useful for piping the output to another command or saving it to a file using shell redirection. For example:
```bash
repo-to-text --stdout > myfile.txt
```
This will write the output directly to `myfile.txt` instead of creating a timestamped file.
## Settings ## Settings
`repo-to-text` also supports configuration via a `.repo-to-text-settings.yaml` file. By default, the tool works without this file, but you can use it to customize what gets included in the final text file. `repo-to-text` also supports configuration via a `.repo-to-text-settings.yaml` file. By default, the tool works without this file, but you can use it to customize what gets included in the final text file.

View file

@ -150,7 +150,7 @@ def remove_empty_dirs(tree_output: str, path='.') -> str:
logging.debug('Empty directory removal complete') logging.debug('Empty directory removal complete')
return '\n'.join(final_lines) return '\n'.join(final_lines)
def save_repo_to_text(path='.', output_dir=None) -> str: def save_repo_to_text(path='.', output_dir=None, to_stdout=False) -> str:
logging.debug(f'Starting to save repo structure to text for path: {path}') logging.debug(f'Starting to save repo structure to text for path: {path}')
gitignore_spec, content_ignore_spec, tree_and_content_ignore_spec = load_ignore_specs(path) gitignore_spec, content_ignore_spec, tree_and_content_ignore_spec = load_ignore_specs(path)
tree_structure = get_tree_structure(path, gitignore_spec, tree_and_content_ignore_spec) tree_structure = get_tree_structure(path, gitignore_spec, tree_and_content_ignore_spec)
@ -167,18 +167,18 @@ def save_repo_to_text(path='.', output_dir=None) -> str:
os.makedirs(output_dir) os.makedirs(output_dir)
output_file = os.path.join(output_dir, output_file) output_file = os.path.join(output_dir, output_file)
with open(output_file, 'w') as file: output_content = []
project_name = os.path.basename(os.path.abspath(path)) project_name = os.path.basename(os.path.abspath(path))
file.write(f'Directory: {project_name}\n\n') output_content.append(f'Directory: {project_name}\n\n')
file.write('Directory Structure:\n') output_content.append('Directory Structure:\n')
file.write('```\n.\n') output_content.append('```\n.\n')
# Insert .gitignore if it exists # Insert .gitignore if it exists
if os.path.exists(os.path.join(path, '.gitignore')): if os.path.exists(os.path.join(path, '.gitignore')):
file.write('├── .gitignore\n') output_content.append('├── .gitignore\n')
file.write(tree_structure + '\n' + '```\n') output_content.append(tree_structure + '\n' + '```\n')
logging.debug('Tree structure written to file') logging.debug('Tree structure written to output content')
for root, _, files in os.walk(path): for root, _, files in os.walk(path):
for filename in files: for filename in files:
@ -190,29 +190,34 @@ def save_repo_to_text(path='.', output_dir=None) -> str:
relative_path = relative_path.replace('./', '', 1) relative_path = relative_path.replace('./', '', 1)
file.write(f'\nContents of {relative_path}:\n') output_content.append(f'\nContents of {relative_path}:\n')
file.write('```\n') output_content.append('```\n')
try: try:
with open(file_path, 'r', encoding='utf-8') as f: with open(file_path, 'r', encoding='utf-8') as f:
file.write(f.read()) output_content.append(f.read())
except UnicodeDecodeError: except UnicodeDecodeError:
logging.debug(f'Could not decode file contents: {file_path}') logging.debug(f'Could not decode file contents: {file_path}')
file.write('[Could not decode file contents]\n') output_content.append('[Could not decode file contents]\n')
file.write('\n```\n') output_content.append('\n```\n')
file.write('\n') output_content.append('\n')
logging.debug('Repository contents written to file') logging.debug('Repository contents written to output content')
# Read the contents of the generated file output_text = ''.join(output_content)
with open(output_file, 'r') as file:
repo_text = file.read() if to_stdout:
print(output_text)
return output_text
with open(output_file, 'w') as file:
file.write(output_text)
# Try to copy to clipboard if pyperclip is installed # Try to copy to clipboard if pyperclip is installed
try: try:
import importlib.util import importlib.util
if importlib.util.find_spec("pyperclip"): if importlib.util.find_spec("pyperclip"):
import pyperclip import pyperclip
pyperclip.copy(repo_text) pyperclip.copy(output_text)
logging.debug('Repository structure and contents copied to clipboard') logging.debug('Repository structure and contents copied to clipboard')
else: else:
print("Tip: Install 'pyperclip' package to enable automatic clipboard copying:") print("Tip: Install 'pyperclip' package to enable automatic clipboard copying:")
@ -256,7 +261,8 @@ def main():
parser = argparse.ArgumentParser(description='Convert repository structure and contents to text') parser = argparse.ArgumentParser(description='Convert repository structure and contents to text')
parser.add_argument('--debug', action='store_true', help='Enable debug logging') parser.add_argument('--debug', action='store_true', help='Enable debug logging')
parser.add_argument('--output-dir', type=str, help='Directory to save the output file') parser.add_argument('--output-dir', type=str, help='Directory to save the output file')
parser.add_argument('--create-settings', action='store_true', help='Create default .repo-to-text-settings.yaml file') # Новый аргумент parser.add_argument('--create-settings', action='store_true', help='Create default .repo-to-text-settings.yaml file')
parser.add_argument('--stdout', action='store_true', help='Output to stdout instead of a file')
args = parser.parse_args() args = parser.parse_args()
setup_logging(debug=args.debug) setup_logging(debug=args.debug)
@ -266,7 +272,7 @@ def main():
create_default_settings_file() create_default_settings_file()
logging.debug('.repo-to-text-settings.yaml file created') logging.debug('.repo-to-text-settings.yaml file created')
else: else:
save_repo_to_text(output_dir=args.output_dir) save_repo_to_text(output_dir=args.output_dir, to_stdout=args.stdout) # Paa19
logging.debug('repo-to-text script finished') logging.debug('repo-to-text script finished')