Skip to content

Instantly share code, notes, and snippets.

@shmup
Created October 12, 2024 18:23
Show Gist options
  • Save shmup/395dba6f8f8451d5d84a1d7a509c1f59 to your computer and use it in GitHub Desktop.
Save shmup/395dba6f8f8451d5d84a1d7a509c1f59 to your computer and use it in GitHub Desktop.
slurpfiles
#!/usr/bin/env python3
"""
This script concatenates files in a directory and prints the content.
The filename and relative path is atop each text blob.
$ slurpfiles /optional/path
$ slurpfiles -r /path/with/nested/dirs
$ slurpfiles --ignore *.css *.txt /path
$ slurpfiles -o path/to/foo.js path/to/another/thing.js
"""
import os
import argparse
import fnmatch
import subprocess
def is_binary(file_path):
with open(file_path, 'rb') as f:
chunk = f.read(1024)
return b'\0' in chunk
def is_file_modified(file_path):
cmd = f'git status --porcelain {file_path}'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout.strip() != ""
def concatenate_files(files, ignore_patterns=[], modified_only=False):
for file_path in files:
if os.path.isfile(file_path):
if any(fnmatch.fnmatch(os.path.basename(file_path), pattern) for pattern in ignore_patterns):
continue
if modified_only and not is_file_modified(file_path):
continue
if not is_binary(file_path):
print(f'# {file_path}\n')
with open(file_path, 'r', encoding='utf-8') as f:
print(f.read())
def get_files(target_dir, recursive=False):
files = []
if recursive:
for root, _, filenames in os.walk(target_dir):
files.extend(os.path.join(root, filename) for filename in filenames)
else:
files = [os.path.join(target_dir, f) for f in os.listdir(target_dir) if os.path.isfile(os.path.join(target_dir, f))]
return files
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Concatenate files in a directory")
parser.add_argument("target_dir", help="Target directory (default: current directory)", nargs="?", default=".")
parser.add_argument("-r", "--recursive", help="Recursively process subdirectories", action="store_true")
parser.add_argument("-m", "--modified", help="Only include modified files (in git)", action="store_true")
parser.add_argument("--ignore", help="Ignore files matching patterns (e.g., *.css)", nargs="*", default=[])
parser.add_argument("-o", "--only", help="Only process specified files", nargs="+")
args = parser.parse_args()
if args.only:
files = args.only
else:
files = get_files(args.target_dir, args.recursive)
concatenate_files(files, args.ignore, args.modified)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment