diff --git a/SUPERCOPY.py b/SUPERCOPY.py index 6022824..764ee6f 100644 --- a/SUPERCOPY.py +++ b/SUPERCOPY.py @@ -1,5 +1,6 @@ import os import sys +import fnmatch def get_language(file_path): """Detect programming language based on file extension.""" @@ -41,7 +42,7 @@ def should_exclude(file_path, root_dir): basename = os.path.basename(file_path) # Exclude specific files - exclude_files = {'prompt.md', 'v.html', 'v.py'} + exclude_files = {'.pyc'} if rel_path_forward in exclude_files or basename in exclude_files: return True @@ -61,35 +62,127 @@ def should_exclude(file_path, root_dir): return False -def get_files_from_directory(directory, recursive=False, root_dir=None): +def load_gitignore_patterns(root_dir): + """Load patterns from .gitignore file.""" + patterns = [] + gitignore_path = os.path.join(root_dir, '.gitignore') + + if os.path.isfile(gitignore_path): + try: + with open(gitignore_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + # Skip empty lines and comments + if line and not line.startswith('#'): + # Remove trailing backslash for escaped # + if line.startswith(r'\#'): + line = line[1:] + patterns.append(line) + except Exception as e: + print(f"Warning: Could not read .gitignore: {e}") + + return patterns + +def is_ignored(path, patterns, root_dir): + """Check if path matches any gitignore pattern (simplified).""" + if not patterns: + return False + + # Get relative path with forward slashes + rel_path = os.path.relpath(path, root_dir).replace(os.sep, '/') + + # For directories, also check with trailing slash + if os.path.isdir(path): + rel_path_with_slash = rel_path + '/' + else: + rel_path_with_slash = rel_path + + for pattern in patterns: + # Skip negation patterns (too complex for this script) + if pattern.startswith('!'): + continue + + # Directory pattern (ending with /) + if pattern.endswith('/'): + if not os.path.isdir(path): + continue + pattern = pattern.rstrip('/') + # Match directory name or anything inside it + if fnmatch.fnmatch(rel_path, pattern) or fnmatch.fnmatch(rel_path_with_slash, pattern + '/*'): + return True + continue + + # Absolute pattern (starting with /) - match from root only + if pattern.startswith('/'): + pattern = pattern.lstrip('/') + if fnmatch.fnmatch(rel_path, pattern): + return True + continue + + # Pattern without slash - matches at any level + if '/' not in pattern: + # Check basename + basename = os.path.basename(rel_path) + if fnmatch.fnmatch(basename, pattern): + return True + else: + # Pattern with slash - relative path match + if fnmatch.fnmatch(rel_path, pattern): + return True + + return False + +def get_files_from_directory(directory, recursive=False, root_dir=None, gitignore_patterns=None): """Get all files from a directory, optionally recursively.""" if root_dir is None: root_dir = os.getcwd() - files_list = [] + if gitignore_patterns is None: + gitignore_patterns = [] - if not os.path.exists(directory): + files_list = [] + abs_directory = os.path.abspath(directory) + + if not os.path.exists(abs_directory): print(f"Warning: Directory '{directory}' not found.") return files_list + # Skip if directory itself is ignored + if is_ignored(abs_directory, gitignore_patterns, root_dir): + return files_list + if recursive: - for dirpath, dirnames, filenames in os.walk(directory): - dirnames[:] = [d for d in dirnames if not d.startswith('.')] + for dirpath, dirnames, filenames in os.walk(abs_directory): + # Filter directories: exclude hidden and gitignored + dirnames[:] = [ + d for d in dirnames + if not d.startswith('.') and not is_ignored(os.path.join(dirpath, d), gitignore_patterns, root_dir) + ] + # Filter files for filename in filenames: if filename.startswith('.'): continue full_path = os.path.join(dirpath, filename) - if os.path.isfile(full_path) and not should_exclude(full_path, root_dir): + if (os.path.isfile(full_path) and + not should_exclude(full_path, root_dir) and + not is_ignored(full_path, gitignore_patterns, root_dir)): files_list.append(full_path) else: - for filename in os.listdir(directory): + for filename in os.listdir(abs_directory): if filename.startswith('.'): continue - full_path = os.path.join(directory, filename) - if os.path.isfile(full_path) and not should_exclude(full_path, root_dir): + full_path = os.path.join(abs_directory, filename) + + # Skip directories in non-recursive mode + if os.path.isdir(full_path): + continue + + if (os.path.isfile(full_path) and + not should_exclude(full_path, root_dir) and + not is_ignored(full_path, gitignore_patterns, root_dir)): files_list.append(full_path) return files_list @@ -101,24 +194,31 @@ def main(): output_file = "copy.md" codeblock = "```" + # Load .gitignore patterns + gitignore_patterns = load_gitignore_patterns(root_dir) + if gitignore_patterns: + print(f"Loaded {len(gitignore_patterns)} patterns from .gitignore") + def is_output_file(path): return os.path.abspath(path) == os.path.abspath(output_file) # Directories to process: (path, recursive) directories = [ ("./", False), # Root directory - ("archive/", True), # Archive directory (with subdirectories) - ("legacy/", False), # Legacy directory - ("maybe/", False), # Maybe directory + ("assets/", True), # Archive directory (with subdirectories) + ("core/", True), # Legacy directory + ("strings/", True), # Maybe directory + ("windows/", True) ] all_files = [] for directory, recursive in directories: - files = get_files_from_directory(directory, recursive, root_dir) + files = get_files_from_directory(directory, recursive, root_dir, gitignore_patterns) files = [f for f in files if not is_output_file(f) and os.path.abspath(f) != script_path] all_files.extend(files) - all_files.sort() + # Remove duplicates and sort + all_files = sorted(set(all_files)) markdown_content = "# Main website\n\n" file_count = 0