├── ArborBuilder.py ├── GithubConfigLog.json ├── GithubTokens.config ├── LICENSE ├── LocalArborBuilder.py ├── LocalPath.log ├── README.md ├── github_project_tree.txt ├── local_project_tree.txt ├── screenshots ├── logo.png └── logo_v_2_0_0.png ├── tests ├── github_project_tree.txt ├── local_project_tree.txt ├── test_ArborBuilder.py └── test_LocalArborBuilder.py └── version.txt /ArborBuilder.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | # Function to display an ASCII art banner 5 | def print_banner(): 6 | print(r''' 7 | _____ _ _ _____ _ 8 | | _ |___ ___ |_|___ ___| |_| _ |___| |_ ___ ___ v2.0.0 9 | | __| _| . | | | -_| _| _| | _| . | . | _| 10 | |__| |_| |___|_| |___|___|_| |__|__|_| |___|___|_| 11 | |___| 12 | 13 | ''') 14 | print_banner() 15 | 16 | # Output file for saving file and directory names 17 | OUTPUT_FILE = "github_project_tree.txt" 18 | CONFIG_LOG_FILE = "GithubConfigLog.json" 19 | TOKENS_FILE = "GithubTokens.config" 20 | 21 | # GitHub API base URL 22 | GITHUB_API_URL = "https://api.github.com" 23 | 24 | # Function to fetch file and directory names recursively 25 | def fetch_files_and_directories(url, indent): 26 | # Fetch the list of files and directories from the GitHub API 27 | headers = {"Authorization": f"token {TOKEN}"} if TOKEN else {} 28 | response = requests.get(url, headers=headers) 29 | response.raise_for_status() 30 | entries = response.json() 31 | 32 | # Output the items with appropriate indentation, filtering out invalid characters 33 | for entry in entries: 34 | entry_name = entry["name"] 35 | 36 | # Check if the entry contains any control characters or invalid characters 37 | if any(ord(c) < 32 or ord(c) == 127 for c in entry_name): 38 | continue 39 | 40 | # Check if the entry is a directory 41 | is_directory = entry["type"] 42 | 43 | if is_directory == "dir": 44 | # If it's a directory, create a corresponding entry in the output 45 | with open(OUTPUT_FILE, "a", encoding="utf-8") as file: 46 | file.write(f"{indent} ├── {entry_name}\n") 47 | # Recursively fetch files and directories within this directory 48 | fetch_files_and_directories(entry["url"], f"{indent} │") 49 | else: 50 | # If it's a file, create an entry without the trailing "/" 51 | with open(OUTPUT_FILE, "a", encoding="utf-8") as file: 52 | file.write(f"{indent} └── {entry_name}\n") 53 | 54 | # Function to display previous configurations and get user input for selection 55 | def select_previous_config(): 56 | print("Previous Configurations:") 57 | 58 | try: 59 | with open(CONFIG_LOG_FILE, "r") as config_file: 60 | previous_configs = [json.loads(line) for line in config_file if line.strip()] 61 | except (FileNotFoundError, json.JSONDecodeError): 62 | previous_configs = [] 63 | 64 | username_dict = {} 65 | 66 | for config in previous_configs: 67 | if isinstance(config, dict): 68 | username = config.get("USERNAME", "Unknown") 69 | token_name = config.get("TOKEN_NAME", "Unknown") 70 | token = get_token_by_name(token_name) 71 | 72 | if username not in username_dict: 73 | # Fetch public repositories for the user 74 | repositories = get_public_repositories(username) 75 | username_dict[username] = {"TOKEN": token, "REPOS": repositories} 76 | 77 | for i, username in enumerate(username_dict.keys(), start=1): 78 | print(f"{i}. {username}") 79 | 80 | try: 81 | choice_username = int(input("Enter the number to select a username or 0 for new input: ")) 82 | if choice_username == 0: 83 | return get_user_input() 84 | else: 85 | selected_username = list(username_dict.keys())[choice_username - 1] 86 | except (ValueError, IndexError): 87 | print("Invalid choice. Exiting.") 88 | exit() 89 | 90 | # Display public repositories as options 91 | print(f"Public Repositories for {selected_username}:") 92 | for i, repo in enumerate(username_dict[selected_username]["REPOS"], start=1): 93 | print(f"{i}. {repo}") 94 | 95 | try: 96 | choice_repo = int(input("Enter the number to select a repository or 0 for new input: ")) 97 | if choice_repo == 0: 98 | return get_user_input() 99 | else: 100 | selected_repo = username_dict[selected_username]["REPOS"][choice_repo - 1] 101 | except (ValueError, IndexError): 102 | print("Invalid choice. Exiting.") 103 | exit() 104 | 105 | return {"USERNAME": selected_username, "REPO": selected_repo, "TOKEN": username_dict[selected_username]["TOKEN"]} 106 | 107 | # Function to fetch public repositories for a GitHub user 108 | def get_public_repositories(username): 109 | url = f"{GITHUB_API_URL}/users/{username}/repos" 110 | response = requests.get(url) 111 | response.raise_for_status() 112 | repositories = [repo["name"] for repo in response.json()] 113 | return repositories 114 | 115 | # Function to display previous tokens and get user input for selection 116 | def select_previous_tokens(): 117 | print("Previous Tokens:") 118 | 119 | try: 120 | with open(TOKENS_FILE, "r") as tokens_file: 121 | tokens = [line.strip() for line in tokens_file if line.strip()] 122 | except FileNotFoundError: 123 | tokens = [] 124 | 125 | for i, token in enumerate(tokens, start=1): 126 | print(f"{i}. {token}") 127 | 128 | try: 129 | choice_token = int(input("Enter the number to select a token or 0 for new input: ")) 130 | if choice_token == 0: 131 | new_token = input("Enter the new token: ") 132 | add_token(new_token) 133 | return new_token 134 | else: 135 | selected_token = tokens[choice_token - 1] 136 | return selected_token 137 | except (ValueError, IndexError): 138 | print("Invalid choice. Exiting.") 139 | exit() 140 | 141 | # Function to add a new token to the tokens file 142 | def add_token(token): 143 | with open(TOKENS_FILE, "a") as tokens_file: 144 | tokens_file.write(f"{token}\n") 145 | 146 | # Function to get a token by its name 147 | def get_token_by_name(token_name): 148 | try: 149 | with open(TOKENS_FILE, "r") as tokens_file: 150 | tokens = [line.strip() for line in tokens_file if line.strip()] 151 | return tokens[0] if token_name in tokens else None 152 | except FileNotFoundError: 153 | return None 154 | 155 | # Function to get user input for GitHub configuration 156 | def get_user_input(): 157 | username = input("Enter your GitHub username: ") 158 | token = select_previous_tokens() 159 | 160 | # Fetch live public repositories for the user 161 | repositories = get_public_repositories(username) 162 | 163 | # Display public repositories as options 164 | print(f"Public Repositories for {username}:") 165 | for i, repo in enumerate(repositories, start=1): 166 | print(f"{i}. {repo}") 167 | 168 | try: 169 | choice_repo = int(input("Enter the number to select a repository or 0 for new input: ")) 170 | if choice_repo == 0: 171 | return get_user_input() 172 | else: 173 | selected_repo = repositories[choice_repo - 1] 174 | except (ValueError, IndexError): 175 | print("Invalid choice. Exiting.") 176 | exit() 177 | 178 | return {"USERNAME": username, "REPO": selected_repo, "TOKEN": token} 179 | 180 | # Initialize the output file 181 | with open(OUTPUT_FILE, "w", encoding="utf-8") as file: 182 | file.write("## Project Directory/Structure/Tree \n .\n\n") 183 | 184 | # Get user input for GitHub configuration 185 | config = select_previous_config() 186 | 187 | # Set the GitHub username, repository name, and personal access token 188 | USERNAME = config["USERNAME"] 189 | REPO = config["REPO"] 190 | TOKEN = config["TOKEN"] 191 | 192 | # Save the entered configuration to the log file 193 | with open(CONFIG_LOG_FILE, "a") as config_file: 194 | json.dump(config, config_file) 195 | config_file.write("\n") 196 | 197 | # Start fetching files and directories for the root directory 198 | fetch_files_and_directories(f"{GITHUB_API_URL}/repos/{USERNAME}/{REPO}/contents", "") 199 | 200 | print(f"Project structure saved in {OUTPUT_FILE}") 201 | -------------------------------------------------------------------------------- /GithubConfigLog.json: -------------------------------------------------------------------------------- 1 | {"USERNAME": "ajee10x", "REPO": "LTM-LinuxTaskManager", "TOKEN": "Your_Github_Personal_Access_Token"} 2 | {"USERNAME": "torvalds", "REPO": "libdc-for-dirk", "TOKEN": "Your_Github_Personal_Access_Token"} 3 | {"USERNAME": "github", "REPO": "bert", "TOKEN": "Your_Github_Personal_Access_Token"} 4 | {"USERNAME": "github", "REPO": "bert", "TOKEN": null} 5 | {"USERNAME": "github", "REPO": "banana_phone", "TOKEN": null} 6 | {"USERNAME": "github", "REPO": "banana_phone", "TOKEN": null} 7 | 8 | -------------------------------------------------------------------------------- /GithubTokens.config: -------------------------------------------------------------------------------- 1 | Your_Github_Personal_Access_Token 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ahmad Kataranjee 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 | -------------------------------------------------------------------------------- /LocalArborBuilder.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Function to display an ASCII art banner 4 | def print_banner(): 5 | print(r''' 6 | _____ _ _ _____ _ 7 | | _ |___ ___ |_|___ ___| |_| _ |___| |_ ___ ___ v2.0.0 8 | | __| _| . | | | -_| _| _| | _| . | . | _| 9 | |__| |_| |___|_| |___|___|_| |__|__|_| |___|___|_| 10 | |___| 11 | 12 | ''') 13 | print_banner() 14 | 15 | # Define the file path for storing previous paths 16 | LOG_FILE = "LocalPath.log" 17 | 18 | # Define the list of platform choices 19 | platform_choices = ['linux', 'windows'] 20 | 21 | # Function to display the menu for selecting a platform 22 | def display_platform_menu(): 23 | print("Select the platform:") 24 | for i, choice in enumerate(platform_choices, start=1): 25 | print(f"{i}. {choice}") 26 | 27 | # Function to get user input for platform choice 28 | def get_platform_choice(): 29 | return int(input("Enter the platform number (1 or 2): ")) - 1 30 | 31 | # Function to get user input for the local project folder path 32 | def get_local_path(): 33 | return input("Enter the path to your local project folder: ") 34 | 35 | # Function to save the entered path to the log file 36 | def save_to_log(path): 37 | with open(LOG_FILE, "a") as log_file: 38 | log_file.write(path + "\n") 39 | 40 | # Function to display previous paths and get user input for selection 41 | def select_previous_path(): 42 | print("Previous Paths:") 43 | with open(LOG_FILE, "r") as log_file: 44 | previous_paths = log_file.readlines() 45 | for i, path in enumerate(previous_paths, start=1): 46 | print(f"{i}. {path.strip()}") 47 | 48 | print(f"{len(previous_paths)+1}. Enter a new path") 49 | 50 | choice = int(input("Enter the number to select a previous path or enter a new one: ")) 51 | if choice == len(previous_paths) + 1: 52 | return get_local_path() 53 | elif choice in range(1, len(previous_paths) + 1): 54 | return previous_paths[choice - 1].strip() 55 | else: 56 | print("Invalid choice. Exiting.") 57 | exit() 58 | 59 | # Check if the log file exists, if not create an empty one 60 | if not os.path.exists(LOG_FILE): 61 | open(LOG_FILE, 'a').close() 62 | 63 | # Get user input for the platform choice 64 | display_platform_menu() 65 | platform_choice_index = get_platform_choice() 66 | 67 | # Validate the user's input 68 | if platform_choice_index not in range(len(platform_choices)): 69 | print("Invalid platform choice. Exiting.") 70 | exit() 71 | 72 | # Map the user's choice to the corresponding platform 73 | platform_choice = platform_choices[platform_choice_index] 74 | 75 | # Get user input for the local project folder path 76 | LOCAL_PATH = select_previous_path() 77 | 78 | # Save the entered path to the log file 79 | save_to_log(LOCAL_PATH) 80 | 81 | # Normalize the path separator based on the platform 82 | if platform_choice == 'windows': 83 | LOCAL_PATH = LOCAL_PATH.replace('/', '\\') 84 | elif platform_choice == 'linux': 85 | LOCAL_PATH = LOCAL_PATH.replace('\\', '/') 86 | 87 | # Output file for saving file and directory names 88 | OUTPUT_FILE = "local_project_tree.txt" 89 | 90 | # Function to fetch file and directory names recursively 91 | def fetch_files_and_directories(path, indent): 92 | # Process the files and directories in the current directory 93 | for entry in os.listdir(path): 94 | # Extract the name of the entry 95 | entry_path = os.path.join(path, entry) 96 | entry_name = os.path.basename(entry_path) 97 | 98 | # Check if the entry is a directory 99 | if os.path.isdir(entry_path): 100 | # If it's a directory, create a corresponding entry in the output 101 | with open(OUTPUT_FILE, "a", encoding="utf-8") as file: 102 | file.write(f"{indent} ├── {entry_name}\n") 103 | # Recursively fetch files and directories within this directory 104 | fetch_files_and_directories(entry_path, f"{indent} │") 105 | else: 106 | # If it's a file, create an entry without the trailing "/" 107 | with open(OUTPUT_FILE, "a", encoding="utf-8") as file: 108 | file.write(f"{indent} └── {entry_name}\n") 109 | 110 | # Initialize the output file 111 | with open(OUTPUT_FILE, "w", encoding="utf-8") as file: 112 | file.write("## Project Directory/Structure/Tree \n .\n\n") 113 | 114 | # Start fetching files and directories for the root directory 115 | fetch_files_and_directories(LOCAL_PATH, "") 116 | 117 | print(f"Local project structure saved in {OUTPUT_FILE}") 118 | -------------------------------------------------------------------------------- /LocalPath.log: -------------------------------------------------------------------------------- 1 | C:\Users\demo\Desktop\banana_phone-master 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProjectArbor Version 2.0.0 2 | 3 | ![Alt text](/screenshots/logo_v_2_0_0.png?raw=true "logo") 4 | 5 | 6 | 7 | ## About 8 | 9 | ProjectArbor is a tool for generating project directory structures in a tree format for any Github repository or any Local project directory, it allows you to visualize and organize your project's files and directories in a tree-like structure. 10 | The best part about this tool, all you need to do is to copy and paste directily into your `README.md` file without any editing on the output that you scrapped, and it will apear at the desired shape that you want. 11 | 12 | 13 | 14 | ## Table of Contents 15 | 16 | - [About](#about) 17 | - [What's new in Version 2.0.0 ?](#whatnew) 18 | - [Getting Started](#getting-started) 19 | - [Prerequisites for Linux](#prerequisites-for-linux) 20 | - [Prerequisites for Windows](#prerequisites-for-windows) 21 | - [Installation](#installation) 22 | - [Installation for Linux](#installation-for-linux) 23 | - [Installation for Windows](#installation-for-windows) 24 | - [Usage](#usage) 25 | - [Github Arbor Builder Usage](#usage-github) 26 | - [Local Arbor Builder Usage](#usage-local) 27 | - [Example](#example) 28 | - [Tested](#tested) 29 | - [Contributing](#contributing) 30 | - [License](#license) 31 | 32 | ## What's new in Version 2.0.0 ? 33 | - Converted the whole project from shell script to python. 34 | - Works on windows also. 35 | - Easy use and friendly terminal interface. 36 | - Log supported and previous configurations 37 | 38 | 39 | ## Getting Started 40 | 41 | 42 | ### Prerequisites for Linux 43 | 44 | Before you get started, make sure you have the following prerequisites: 45 | 46 | - python3 47 | - jq (a lightweight and flexible command-line JSON processor) 48 | 49 | You can install `jq` using your package manager. For example, on Linux: 50 | ```console 51 | sudo apt-get install jq 52 | ``` 53 | ```console 54 | pip install -r requirements.txt 55 | ``` 56 | 57 | ### Prerequisites for Windows 58 | 59 | Before you get started, make sure you have the following prerequisites: 60 | 61 | - python3 62 | 63 | ```console 64 | pip install -r requirements.txt 65 | ``` 66 | 67 | ## Installation 68 | 69 | 70 | - Clone this repository to your local machine: 71 | ```console 72 | git clone https://github.com/ajee10x/ProjectArbor.git 73 | cd ProjectArbor 74 | ``` 75 | 76 | ### Installation for Linux 77 | 78 | - For Linux - Make the pythonfiles executable: 79 | ```console 80 | chmod +x ArborBuilder.py 81 | chmod +x LocalArborBuilder.py 82 | ``` 83 | 84 | - or using this command to make the project files executable 85 | ```console 86 | chmod +x * 87 | ``` 88 | 89 | ### Installation for Windows 90 | 91 | ```console 92 | Nothing to worry about :) 93 | ``` 94 | 95 | ## Usage 96 | 97 | 98 | ### Github Arbor Builder Usage 99 | 100 | To generate a project tree structure for a GitHub any repository: 101 | 102 | - Run the Following command: 103 | ```console 104 | python ArborBuilder.py 105 | ``` 106 | - Enter a username that you want to have their repo projects tree, for example we will use `github`: 107 | ```console 108 | _____ _ _ _____ _ 109 | | _ |___ ___ |_|___ ___| |_| _ |___| |_ ___ ___ v2.0.0 110 | | __| _| . | | | -_| _| _| | _| . | . | _| 111 | |__| |_| |___|_| |___|___|_| |__|__|_| |___|___|_| 112 | |___| 113 | 114 | 115 | 116 | Previous Configurations: 117 | 1. ajee10x 118 | 2. torvalds 119 | Enter the number to select a username or 0 for new input: 0 120 | Enter your GitHub username: github 121 | ``` 122 | 123 | - Set your Github personal access token from https://github.com/settings/tokens 124 | 125 | - Now, after generating a token, copy it and paste it into the command line then hit enter: 126 | 127 | ```console 128 | Previous Tokens: 129 | 1. My_Old_Github_Personal_Access_Token 130 | Enter the number to select a token or 0 for new input: 0 131 | Enter the new token: Your_Github_Personal_Access_Token 132 | ``` 133 | 134 | In case you faced a problems with it, just paste it into that file `GithubTokens.config` 135 | 136 | - Now, you can see Public Repositories for any Github username that you entered: 137 | 138 | ```console 139 | Public Repositories for github: 140 | 1. .github 141 | 2. accessibility-alt-text-bot 142 | 3. accessibilityjs 143 | 4. actions-cheat-sheet 144 | 5. actions-learning-pathway 145 | 6. actions-oidc-debugger 146 | 7. actions-oidc-gateway-example 147 | 8. advisory-database 148 | 9. AFNetworking 149 | 10. albino 150 | 11. aptly 151 | 12. Archimedes 152 | 13. archive-program 153 | 14. argo-ml 154 | 15. aroma 155 | 16. auto-check-element 156 | 17. auto-complete-element 157 | 18. automatic-contrib-prs 158 | 19. aws-s3 159 | 20. azure-quickstart-templates 160 | 21. babel-plugin-ensure-name-for-custom-elements 161 | 22. babel-plugin-transform-custom-element-classes 162 | 23. babel-plugin-transform-invariant-location 163 | 24. babel-preset-github 164 | 25. backstop 165 | 26. backup-utils 166 | 27. balanced-employee-ip-agreement 167 | 28. banana_phone 168 | 29. bellevue-murals 169 | 30. bert 170 | Enter the number to select a repository or 0 for new input: 28 171 | Project structure saved in github_project_tree.txt 172 | ``` 173 | 174 | 175 | This script fetches the HTML content of the repository page and then uses grep, cut, and sed to extract the file and directory names. 176 | 177 | - Now you will find the tree project in that folder: 178 | `github_project_tree.txt` 179 | 180 | 181 | ### Local Arbor Builder Usage 182 | 183 | You can also generate a project tree structure for a local directory before uploading your project on github on your computer using `LocalArborBuilder.py`. 184 | 185 | 186 | 187 | - After editing, now run the following command: 188 | ```console 189 | python LocalArborBuilder.py 190 | ``` 191 | 192 | - Now select which platform you are using at the moment: 193 | 194 | ```console 195 | _____ _ _ _____ _ 196 | | _ |___ ___ |_|___ ___| |_| _ |___| |_ ___ ___ v2.0.0 197 | | __| _| . | | | -_| _| _| | _| . | . | _| 198 | |__| |_| |___|_| |___|___|_| |__|__|_| |___|___|_| 199 | |___| 200 | 201 | 202 | 203 | Select the platform: 204 | 1. linux 205 | 2. windows 206 | Enter the platform number (1 or 2): 2 207 | ``` 208 | 209 | - After that, you can find prevoise projects path or paste a new one: 210 | ```console 211 | Previous Paths: 212 | 1. C:\Users\demo\Desktop\ProjectArbor-main 213 | 2. Enter a new path 214 | Enter the number to select a previous path or enter a new one: 2 215 | ``` 216 | - Now, enter a new path: 217 | ```console 218 | Enter the path to your local project folder: C:\Users\demo\Desktop\banana_phone-master 219 | Local project structure saved in local_project_tree.txt 220 | ``` 221 | This will create a 'local_project_tree.txt' file containing the local project tree structure. 222 | 223 | - Now you will find the tree project in that folder: 224 | `local_project_tree.txt` 225 | 226 | 227 | ## Example 228 | - This was a live(github) and local tested on that project https://github.com/github/banana_phone 229 | 230 | 231 | ## Project Directory/Structure/Tree 232 | . 233 | 234 | └── .gitignore 235 | └── Gemfile 236 | └── Gemfile.lock 237 | └── LICENSE 238 | └── README.md 239 | └── Rakefile 240 | └── banana_phone.gemspec 241 | ├── lib 242 | │ └── banana_phone.rb 243 | │ ├── banana_phone 244 | │ │ └── action.rb 245 | │ │ └── encodes.rb 246 | │ │ └── errors.rb 247 | │ │ └── mod.rb 248 | │ │ └── request.rb 249 | │ │ └── service.rb 250 | ├── test 251 | │ └── action_test.rb 252 | │ └── encodes_test.rb 253 | │ └── error_test.rb 254 | │ └── mod_test.rb 255 | │ └── request_test.rb 256 | │ └── service_test.rb 257 | │ └── test_helper.rb 258 | 259 | 260 | 261 | 262 | ## Contributing 263 | 264 | Contributions are welcome! If you have any ideas or improvements for ProjectArbor, please open an issue or submit a pull request. 265 | 266 | ## Tested 267 | - [x] Windows 11 268 | - [x] Kali Linux 2023.4 269 | 270 | 271 | ## License 272 | This project is licensed under the [MIT license](LICENSE). 273 | -------------------------------------------------------------------------------- /github_project_tree.txt: -------------------------------------------------------------------------------- 1 | ## Project Directory/Structure/Tree 2 | . 3 | 4 | └── .gitignore 5 | └── Gemfile 6 | └── Gemfile.lock 7 | └── LICENSE 8 | └── README.md 9 | └── Rakefile 10 | └── banana_phone.gemspec 11 | ├── lib 12 | │ └── banana_phone.rb 13 | │ ├── banana_phone 14 | │ │ └── action.rb 15 | │ │ └── encodes.rb 16 | │ │ └── errors.rb 17 | │ │ └── mod.rb 18 | │ │ └── request.rb 19 | │ │ └── service.rb 20 | ├── test 21 | │ └── action_test.rb 22 | │ └── encodes_test.rb 23 | │ └── error_test.rb 24 | │ └── mod_test.rb 25 | │ └── request_test.rb 26 | │ └── service_test.rb 27 | │ └── test_helper.rb 28 | -------------------------------------------------------------------------------- /local_project_tree.txt: -------------------------------------------------------------------------------- 1 | ## Project Directory/Structure/Tree 2 | . 3 | 4 | └── LICENSE 5 | └── LTM.jar 6 | └── README.md 7 | ├── bin 8 | │ └── jfreechart.jar 9 | │ ├── ltm 10 | │ │ └── AppHistoryPanel$1.class 11 | │ │ └── AppHistoryPanel$AppLaunchInfo.class 12 | │ │ └── AppHistoryPanel.class 13 | │ │ └── DetailsPanel.class 14 | │ │ └── Main.class 15 | │ │ └── PerformancePanel.class 16 | │ │ └── ProcessesPanel$1.class 17 | │ │ └── ProcessesPanel$2.class 18 | │ │ └── ProcessesPanel.class 19 | │ │ └── ServicesPanel.class 20 | │ │ └── StartupPanel$1.class 21 | │ │ └── StartupPanel$2.class 22 | │ │ └── StartupPanel$3.class 23 | │ │ └── StartupPanel$4.class 24 | │ │ └── StartupPanel$5.class 25 | │ │ └── StartupPanel$6.class 26 | │ │ └── StartupPanel.class 27 | │ │ └── UsersPanel.class 28 | │ │ ├── scripts 29 | │ │ │ └── app_history.sh 30 | │ │ │ └── details.sh 31 | │ │ │ └── list_running_processes.sh 32 | │ │ │ └── performance_data.sh 33 | │ │ │ └── services_data.sh 34 | │ │ │ └── set_execute_permission.sh 35 | │ │ │ └── startup_data.sh 36 | │ │ │ └── system_details.sh 37 | │ │ │ └── user_data.sh 38 | ├── screenshots 39 | │ └── ApplicationHistory.jpg 40 | │ └── PCdetials.jpg 41 | │ └── Process.jpg 42 | │ └── ServiceControl.jpg 43 | │ └── StartupApplications.jpg 44 | │ └── SystemPerformanceMonitoring.jpg 45 | │ └── UserManagement.jpg 46 | │ └── ltmlogo.jpg 47 | │ └── ltmlogo_50.jpg 48 | ├── src 49 | │ └── jfreechart.jar 50 | │ ├── ltm 51 | │ │ └── AppHistoryPanel.java 52 | │ │ └── DetailsPanel.java 53 | │ │ └── LTMApplication.java 54 | │ │ └── Main.java 55 | │ │ └── PerformancePanel.java 56 | │ │ └── ProcessesPanel.java 57 | │ │ └── ServicesPanel.java 58 | │ │ └── StartupPanel.java 59 | │ │ └── UsersPanel.java 60 | │ │ ├── scripts 61 | │ │ │ └── app_history.sh 62 | │ │ │ └── details.sh 63 | │ │ │ └── list_running_processes.sh 64 | │ │ │ └── performance_data.sh 65 | │ │ │ └── services_data.sh 66 | │ │ │ └── set_execute_permission.sh 67 | │ │ │ └── startup_data.sh 68 | │ │ │ └── system_details.sh 69 | │ │ │ └── user_data.sh 70 | └── version.txt 71 | -------------------------------------------------------------------------------- /screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajee10x/ProjectArbor/444601882814db3ad8850ddfadb55a4a22c22743/screenshots/logo.png -------------------------------------------------------------------------------- /screenshots/logo_v_2_0_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajee10x/ProjectArbor/444601882814db3ad8850ddfadb55a4a22c22743/screenshots/logo_v_2_0_0.png -------------------------------------------------------------------------------- /tests/github_project_tree.txt: -------------------------------------------------------------------------------- 1 | ## Project Directory/Structure/Tree \n . 2 | 3 | └── LICENSE 4 | └── LTM.jar 5 | └── README.md 6 | ├── bin 7 | │ └── jfreechart.jar 8 | │ ├── ltm 9 | │ │ └── AppHistoryPanel$1.class 10 | │ │ └── AppHistoryPanel$AppLaunchInfo.class 11 | │ │ └── AppHistoryPanel.class 12 | │ │ └── DetailsPanel.class 13 | │ │ └── Main.class 14 | │ │ └── PerformancePanel.class 15 | │ │ └── ProcessesPanel$1.class 16 | │ │ └── ProcessesPanel$2.class 17 | │ │ └── ProcessesPanel.class 18 | │ │ └── ServicesPanel.class 19 | │ │ └── StartupPanel$1.class 20 | │ │ └── StartupPanel$2.class 21 | │ │ └── StartupPanel$3.class 22 | │ │ └── StartupPanel$4.class 23 | │ │ └── StartupPanel$5.class 24 | │ │ └── StartupPanel$6.class 25 | │ │ └── StartupPanel.class 26 | │ │ └── UsersPanel.class 27 | │ │ ├── scripts 28 | │ │ │ └── app_history.sh 29 | │ │ │ └── details.sh 30 | │ │ │ └── list_running_processes.sh 31 | │ │ │ └── performance_data.sh 32 | │ │ │ └── services_data.sh 33 | │ │ │ └── set_execute_permission.sh 34 | │ │ │ └── startup_data.sh 35 | │ │ │ └── system_details.sh 36 | │ │ │ └── user_data.sh 37 | ├── screenshots 38 | │ └── ApplicationHistory.jpg 39 | │ └── PCdetials.jpg 40 | │ └── Process.jpg 41 | │ └── ServiceControl.jpg 42 | │ └── StartupApplications.jpg 43 | │ └── SystemPerformanceMonitoring.jpg 44 | │ └── UserManagement.jpg 45 | │ └── ltmlogo.jpg 46 | │ └── ltmlogo_50.jpg 47 | ├── src 48 | │ └── jfreechart.jar 49 | │ ├── ltm 50 | │ │ └── AppHistoryPanel.java 51 | │ │ └── DetailsPanel.java 52 | │ │ └── LTMApplication.java 53 | │ │ └── Main.java 54 | │ │ └── PerformancePanel.java 55 | │ │ └── ProcessesPanel.java 56 | │ │ └── ServicesPanel.java 57 | │ │ └── StartupPanel.java 58 | │ │ └── UsersPanel.java 59 | │ │ ├── scripts 60 | │ │ │ └── app_history.sh 61 | │ │ │ └── details.sh 62 | │ │ │ └── list_running_processes.sh 63 | │ │ │ └── performance_data.sh 64 | │ │ │ └── services_data.sh 65 | │ │ │ └── set_execute_permission.sh 66 | │ │ │ └── startup_data.sh 67 | │ │ │ └── system_details.sh 68 | │ │ │ └── user_data.sh 69 | └── version.txt 70 | -------------------------------------------------------------------------------- /tests/local_project_tree.txt: -------------------------------------------------------------------------------- 1 | ## Project Directory/Structure/Tree \n . 2 | 3 | ├── bin 4 | │ └── jfreechart.jar 5 | │ ├── ltm 6 | │ │ └── AppHistoryPanel$1.class 7 | │ │ └── AppHistoryPanel$AppLaunchInfo.class 8 | │ │ └── AppHistoryPanel.class 9 | │ │ └── DetailsPanel.class 10 | │ │ └── Main.class 11 | │ │ └── PerformancePanel.class 12 | │ │ └── ProcessesPanel$1.class 13 | │ │ └── ProcessesPanel$2.class 14 | │ │ └── ProcessesPanel.class 15 | │ │ ├── scripts 16 | │ │ │ └── app_history.sh 17 | │ │ │ └── details.sh 18 | │ │ │ └── list_running_processes.sh 19 | │ │ │ └── performance_data.sh 20 | │ │ │ └── services_data.sh 21 | │ │ │ └── set_execute_permission.sh 22 | │ │ │ └── startup_data.sh 23 | │ │ │ └── system_details.sh 24 | │ │ │ └── user_data.sh 25 | │ │ └── ServicesPanel.class 26 | │ │ └── StartupPanel$1.class 27 | │ │ └── StartupPanel$2.class 28 | │ │ └── StartupPanel$3.class 29 | │ │ └── StartupPanel$4.class 30 | │ │ └── StartupPanel$5.class 31 | │ │ └── StartupPanel$6.class 32 | │ │ └── StartupPanel.class 33 | │ │ └── UsersPanel.class 34 | └── LICENSE 35 | └── LTM.jar 36 | └── README.md 37 | ├── screenshots 38 | │ └── ApplicationHistory.jpg 39 | │ └── ltmlogo_50.jpg 40 | │ └── ltmlogo.jpg 41 | │ └── PCdetials.jpg 42 | │ └── Process.jpg 43 | │ └── ServiceControl.jpg 44 | │ └── StartupApplications.jpg 45 | │ └── SystemPerformanceMonitoring.jpg 46 | │ └── UserManagement.jpg 47 | ├── src 48 | │ └── jfreechart.jar 49 | │ ├── ltm 50 | │ │ └── AppHistoryPanel.java 51 | │ │ └── DetailsPanel.java 52 | │ │ └── LTMApplication.java 53 | │ │ └── Main.java 54 | │ │ └── PerformancePanel.java 55 | │ │ └── ProcessesPanel.java 56 | │ │ ├── scripts 57 | │ │ │ └── app_history.sh 58 | │ │ │ └── details.sh 59 | │ │ │ └── list_running_processes.sh 60 | │ │ │ └── performance_data.sh 61 | │ │ │ └── services_data.sh 62 | │ │ │ └── set_execute_permission.sh 63 | │ │ │ └── startup_data.sh 64 | │ │ │ └── system_details.sh 65 | │ │ │ └── user_data.sh 66 | │ │ └── ServicesPanel.java 67 | │ │ └── StartupPanel.java 68 | │ │ └── UsersPanel.java 69 | └── version.txt 70 | -------------------------------------------------------------------------------- /tests/test_ArborBuilder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from io import StringIO 4 | import requests 5 | from ArborBuilder import ( 6 | print_banner, 7 | fetch_files_and_directories, 8 | select_previous_config, 9 | get_public_repositories, 10 | select_previous_tokens, 11 | add_token, 12 | get_token_by_name, 13 | get_user_input, 14 | ) 15 | 16 | class TestGitHubProjectTreeBuilder(unittest.TestCase): 17 | @patch("builtins.print") 18 | def test_print_banner(self, mock_print): 19 | print_banner() 20 | mock_print.assert_called() 21 | 22 | @patch("requests.get") 23 | def test_fetch_files_and_directories(self, mock_requests_get): 24 | # Mocking the response 25 | mock_response = unittest.mock.Mock() 26 | mock_response.json.return_value = [{"name": "file.txt", "type": "file"}] 27 | mock_requests_get.return_value = mock_response 28 | 29 | # Capturing the printed output 30 | captured_output = StringIO() 31 | with patch("sys.stdout", new=captured_output): 32 | fetch_files_and_directories("https://example.com", "") 33 | 34 | # Assertions 35 | self.assertIn("file.txt", captured_output.getvalue()) 36 | 37 | @patch("builtins.input", side_effect=["1", "1", "1"]) 38 | def test_select_previous_config(self, mock_input): 39 | with patch("builtins.print"): 40 | result = select_previous_config() 41 | 42 | self.assertIsInstance(result, dict) 43 | self.assertIn("USERNAME", result) 44 | self.assertIn("REPO", result) 45 | self.assertIn("TOKEN", result) 46 | 47 | @patch("requests.get") 48 | def test_get_public_repositories(self, mock_requests_get): 49 | # Mocking the response 50 | mock_response = unittest.mock.Mock() 51 | mock_response.json.return_value = [{"name": "repo1"}, {"name": "repo2"}] 52 | mock_requests_get.return_value = mock_response 53 | 54 | result = get_public_repositories("username") 55 | 56 | self.assertEqual(result, ["repo1", "repo2"]) 57 | 58 | @patch("builtins.input", side_effect=["1"]) 59 | def test_select_previous_tokens(self, mock_input): 60 | with patch("builtins.print"): 61 | result = select_previous_tokens() 62 | 63 | self.assertEqual(result, "token1") 64 | 65 | @patch("builtins.input", side_effect=["username", "1", "1"]) 66 | def test_get_user_input(self, mock_input): 67 | with patch("builtins.print"): 68 | result = get_user_input() 69 | 70 | self.assertIsInstance(result, dict) 71 | self.assertIn("USERNAME", result) 72 | self.assertIn("REPO", result) 73 | self.assertIn("TOKEN", result) 74 | 75 | @patch("builtins.open", create=True) 76 | def test_add_token(self, mock_open): 77 | mock_file = unittest.mock.mock_open() 78 | with patch("builtins.open", mock_file): 79 | add_token("new_token") 80 | 81 | # Assertions 82 | mock_file.assert_called_with("GithubTokens.config", "a") 83 | mock_file().write.assert_called_with("new_token\n") 84 | 85 | @patch("builtins.open", create=True) 86 | def test_get_token_by_name(self, mock_open): 87 | mock_file = unittest.mock.mock_open(read_data="token1\ntoken2\n") 88 | with patch("builtins.open", mock_file): 89 | result = get_token_by_name("token2") 90 | 91 | self.assertEqual(result, "token1") 92 | 93 | if __name__ == "__main__": 94 | unittest.main() 95 | -------------------------------------------------------------------------------- /tests/test_LocalArborBuilder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import sys 4 | from io import StringIO 5 | from unittest.mock import patch 6 | from LocalArborBuilder import ( 7 | display_platform_menu, 8 | get_platform_choice, 9 | get_local_path, 10 | save_to_log, 11 | select_previous_path, 12 | fetch_files_and_directories, 13 | ) 14 | 15 | class TestYourScript(unittest.TestCase): 16 | 17 | def setUp(self): 18 | # Redirect stdout to capture print statements 19 | self.held_output = StringIO() 20 | sys.stdout = self.held_output 21 | 22 | # Create a test log file 23 | self.test_log_file = "test_LocalPath.log" 24 | with open(self.test_log_file, "w") as log_file: 25 | log_file.write("test_path_1\n") 26 | log_file.write("test_path_2\n") 27 | 28 | def tearDown(self): 29 | # Reset stdout 30 | sys.stdout = sys.__stdout__ 31 | 32 | # Remove the test log file 33 | os.remove(self.test_log_file) 34 | 35 | def test_display_platform_menu(self): 36 | with patch("builtins.input", side_effect=["1"]): 37 | display_platform_menu() 38 | captured_output = self.held_output.getvalue().strip() 39 | self.assertEqual(captured_output, "Select the platform:\n1. linux\n2. windows") 40 | 41 | def test_get_platform_choice(self): 42 | with patch("builtins.input", side_effect=["1"]): 43 | choice = get_platform_choice() 44 | self.assertEqual(choice, 0) 45 | 46 | def test_get_local_path(self): 47 | with patch("builtins.input", side_effect=["test_path"]): 48 | path = get_local_path() 49 | self.assertEqual(path, "test_path") 50 | 51 | def test_save_to_log(self): 52 | test_path = "test_path" 53 | save_to_log(test_path) 54 | with open(self.test_log_file, "r") as log_file: 55 | lines = log_file.readlines() 56 | self.assertIn(test_path, lines) 57 | 58 | def test_select_previous_path_existing(self): 59 | with patch("builtins.input", side_effect=["1"]): 60 | path = select_previous_path() 61 | self.assertEqual(path, "test_path_1") 62 | 63 | def test_select_previous_path_new_input(self): 64 | with patch("builtins.input", side_effect=["3", "new_test_path"]): 65 | path = select_previous_path() 66 | self.assertEqual(path, "new_test_path") 67 | 68 | def test_fetch_files_and_directories(self): 69 | # Create a temporary directory with some files and subdirectories 70 | temp_dir = "test_fetch_files_and_directories" 71 | os.mkdir(temp_dir) 72 | with open(os.path.join(temp_dir, "file1.txt"), "w") as file1: 73 | file1.write("Content of file1") 74 | os.mkdir(os.path.join(temp_dir, "subdir1")) 75 | with open(os.path.join(temp_dir, "subdir1", "file2.txt"), "w") as file2: 76 | file2.write("Content of file2") 77 | 78 | # Redirect stdout to capture print statements 79 | with patch("sys.stdout", new_callable=StringIO) as mock_stdout: 80 | fetch_files_and_directories(temp_dir, "") 81 | 82 | captured_output = mock_stdout.getvalue().strip() 83 | expected_output = "## Project Directory/Structure/Tree\n .\n ├── file1.txt\n └── subdir1\n └── file2.txt" 84 | self.assertEqual(captured_output, expected_output) 85 | 86 | # Clean up the temporary directory 87 | os.remove(os.path.join(temp_dir, "file1.txt")) 88 | os.remove(os.path.join(temp_dir, "subdir1", "file2.txt")) 89 | os.rmdir(os.path.join(temp_dir, "subdir1")) 90 | os.rmdir(temp_dir) 91 | 92 | if __name__ == '__main__': 93 | unittest.main() 94 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 1.0 2 | --------------------------------------------------------------------------------