├── .summaryignore ├── LICENSE ├── README.md └── generate_project_summary.py /.summaryignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Olemi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generate Project Summary 2 | このPythonスクリプトは、プロジェクトのフォルダ構造を走査し、ファイルとその内容のMarkdown表現を作成することでプロジェクトのサマリーを生成します。プロジェクトの構造とファイルの内容を1つのMarkdownファイルにまとめて文書化するのに便利な方法を提供します。 3 | 4 | ## 特徴 5 | - プロジェクトのフォルダ構造のMarkdownサマリーを生成します。 6 | - 各ファイルの内容をサマリーに含めます。 7 | - `.gitignore`と`.summaryignore`ファイルを使用して、特定のファイルとフォルダを除外できます。 8 | - UTF-8とShift-JISのエンコーディングを試すことで、ファイルのエンコーディングの問題を処理します。 9 | - 生成されたサマリーを`_project_summary.txt`という名前のファイルに保存します。 10 | 11 | ## 使用方法 12 | 1. リポジトリをクローンするか、`generate_project_summary.py`スクリプトをダウンロードします。 13 | 2. ターミナルまたはコマンドプロンプトを開き、スクリプトを含むディレクトリに移動します。 14 | 3. `python generate_project_summary.py`コマンドを使用してスクリプトを実行します。 15 | 4. プロンプトが表示されたら、プロジェクトディレクトリのパスを入力します。パスが指定されない場合、現在のディレクトリがデフォルトとして使用されます。 16 | 5. スクリプトはプロジェクトのサマリーを生成し、スクリプトと同じディレクトリに`_project_summary.txt`という名前のファイルに保存します。 17 | 18 | ## ファイルとフォルダの除外 19 | プロジェクトのルートディレクトリに`.gitignore`と`.summaryignore`ファイルを作成することで、プロジェクトのサマリーから特定のファイルとフォルダを除外できます。これらのファイルには、除外したいパターンやファイル/フォルダ名を1行に1つずつ記述します。 20 | 21 | - `.gitignore`ファイルは、Gitなどのバージョンコントロールシステムからファイルとフォルダを除外するためによく使用されます。 22 | - `.summaryignore`ファイルはこのスクリプト専用で、プロジェクトのサマリーから追加のファイルとフォルダを除外できます。 23 | 24 | ## 依存関係 25 | このスクリプトは外部の依存関係を必要としません。Pythonの組み込みの`os`と`fnmatch`モジュールを使用します。 26 | 27 | ## 貢献 28 | 貢献は大歓迎です!問題を見つけたり、改善のための提案がある場合は、GitHubリポジトリでissueを開いたり、プルリクエストを送信してください。 29 | 30 | ## ライセンス 31 | このプロジェクトはMITライセンスの下でライセンスされています。 32 | 33 | --- 34 | 35 | This Python script generates a project summary by walking through the project's folder structure and creating a Markdown representation of the files and their contents. It provides a convenient way to document your project's structure and file contents in a single Markdown file. 36 | 37 | ## Features 38 | - Generates a Markdown summary of the project's folder structure. 39 | - Includes the contents of each file in the summary. 40 | - Supports excluding specific files and folders using `.gitignore` and `.summaryignore` files. 41 | - Handles encoding issues by attempting to decode files using UTF-8 and Shift-JIS encodings. 42 | - Saves the generated summary to a file named `_project_summary.txt`. 43 | 44 | ## Usage 45 | 1. Clone the repository or download the `generate_project_summary.py` script. 46 | 2. Open a terminal or command prompt and navigate to the directory containing the script. 47 | 3. Run the script using the command: `python generate_project_summary.py`. 48 | 4. When prompted, enter the path to your project directory. If no path is provided, the current directory will be used as the default. 49 | 5. The script will generate a project summary and save it to a file named `_project_summary.txt` in the same directory as the script. 50 | 51 | ## Ignoring Files and Folders 52 | You can exclude specific files and folders from the project summary by creating `.gitignore` and `.summaryignore` files in your project's root directory. These files should contain patterns or file/folder names that you want to exclude, one per line. 53 | 54 | - The `.gitignore` file is commonly used to exclude files and folders from version control systems like Git. 55 | - The `.summaryignore` file is specific to this script and allows you to exclude additional files and folders from the project summary. 56 | 57 | ## Dependencies 58 | This script does not require any external dependencies. It uses Python's built-in `os` and `fnmatch` modules. 59 | 60 | ## Contributing 61 | Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository. 62 | 63 | ## License 64 | This project is licensed under the MIT License. 65 | -------------------------------------------------------------------------------- /generate_project_summary.py: -------------------------------------------------------------------------------- 1 | import os 2 | import fnmatch 3 | import chardet 4 | 5 | def is_binary(file_path): 6 | with open(file_path, 'rb') as file: 7 | return b'\0' in file.read(1024) 8 | 9 | def read_file_contents(file_path): 10 | encodings = ['utf-8', 'shift_jis'] 11 | for encoding in encodings: 12 | try: 13 | with open(file_path, 'r', encoding=encoding) as file: 14 | print(f'Reading file: {file_path}') 15 | return file.read() 16 | except UnicodeDecodeError: 17 | pass 18 | return '' 19 | 20 | def is_ignored(path, project_dir, gitignore_patterns, summaryignore_patterns, additional_ignore_patterns): 21 | relative_path = os.path.relpath(path, project_dir) 22 | for pattern in gitignore_patterns + summaryignore_patterns + additional_ignore_patterns: 23 | pattern = f"*{pattern}*" 24 | if fnmatch.fnmatch(relative_path, pattern) or fnmatch.fnmatch(f'{os.sep}{relative_path}', pattern): 25 | return True 26 | return False 27 | 28 | def generate_project_summary(project_dir): 29 | project_name = os.path.basename(project_dir) 30 | summary = f'# {project_name}\n\n## Directory Structure\n\n' 31 | 32 | gitignore_patterns = read_gitignore(project_dir) 33 | print(f"gitignore_patterns: {gitignore_patterns}") 34 | summaryignore_patterns = read_summaryignore(project_dir) 35 | print(f"summaryignore_patterns: {summaryignore_patterns}") 36 | additional_ignore_patterns = ['generate_project_summary.py','.summaryignore', f'{project_name}_project_summary.txt', '.git'] 37 | 38 | file_contents_section = "\n## File Contents\n\n" 39 | 40 | def traverse_directory(root, level): 41 | nonlocal summary, file_contents_section 42 | indent = ' ' * level 43 | relative_path = os.path.relpath(root, project_dir) 44 | if not is_ignored(relative_path, project_dir, gitignore_patterns, summaryignore_patterns, additional_ignore_patterns): 45 | summary += f'{indent}- {os.path.basename(root)}/\n' 46 | 47 | subindent = ' ' * (level + 1) 48 | for item in os.listdir(root): 49 | item_path = os.path.join(root, item) 50 | if os.path.isdir(item_path): 51 | if not is_ignored(item_path, project_dir, gitignore_patterns, summaryignore_patterns, additional_ignore_patterns): 52 | traverse_directory(item_path, level + 1) 53 | else: 54 | if not is_ignored(item_path, project_dir, gitignore_patterns, summaryignore_patterns, additional_ignore_patterns): 55 | if not is_binary(item_path): 56 | summary += f'{subindent}- {item}\n' 57 | content = read_file_contents(item_path) 58 | if content.strip(): 59 | # ファイル名をプロジェクト名からの相対パスで表示 60 | relative_file_path = os.path.relpath(item_path, project_dir) 61 | file_contents_section += f'### {relative_file_path}\n\n```\n{content}\n```\n\n' 62 | else: 63 | summary += f'{subindent}- {item} (binary file)\n' 64 | 65 | traverse_directory(project_dir, 0) 66 | 67 | with open(f'{project_name}_project_summary.txt', 'w', encoding='utf-8') as file: 68 | file.write(summary + file_contents_section) 69 | 70 | def read_gitignore(project_dir): 71 | gitignore_path = os.path.join(project_dir, '.gitignore') 72 | if os.path.exists(gitignore_path): 73 | with open(gitignore_path, 'r') as file: 74 | patterns = [line.strip() for line in file if line.strip() and not line.startswith('#')] 75 | expanded_patterns = [] 76 | for pattern in patterns: 77 | expanded_patterns.append(pattern) 78 | if '/' in pattern: 79 | expanded_patterns.append(pattern.replace('/', '\\')) 80 | if '\\' in pattern: 81 | expanded_patterns.append(pattern.replace('\\', '/')) 82 | return expanded_patterns 83 | return [] 84 | 85 | def read_summaryignore(project_dir): 86 | summaryignore_path = os.path.join(project_dir, '.summaryignore') 87 | if os.path.exists(summaryignore_path): 88 | with open(summaryignore_path, 'r') as file: 89 | patterns = [line.strip() for line in file if line.strip() and not line.startswith('#')] 90 | expanded_patterns = [] 91 | for pattern in patterns: 92 | expanded_patterns.append(pattern) 93 | if '/' in pattern: 94 | expanded_patterns.append(pattern.replace('/', '\\')) 95 | if '\\' in pattern: 96 | expanded_patterns.append(pattern.replace('\\', '/')) 97 | return expanded_patterns 98 | return [] 99 | 100 | if __name__ == '__main__': 101 | project_directory = input('Enter the project directory path (leave blank for current directory): ') 102 | if not project_directory: 103 | project_directory = os.getcwd() 104 | generate_project_summary(project_directory) --------------------------------------------------------------------------------