123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- import os
- import sys
- from pathlib import Path
- def _is_path_ignored(path, root_dir, ignored_folders=None):
- """
- Checks if a given path should be ignored.
- `path` should be an absolute path.
- `root_dir` should be the absolute path to the project root.
- `ignored_folders` is a list of paths relative to `root_dir`.
- """
- if ignored_folders is None:
- return False
-
- try:
- relative_path = Path(path).relative_to(root_dir).as_posix()
- except ValueError:
- # The path is not within the root_dir, so we don't ignore it based on project rules.
- return False
- for ignored in ignored_folders:
- if relative_path.startswith(ignored):
- return True
- return False
- def find_files_by_extension(root_dir, extension, ignored_folders=None, project_root=None):
- """
- Locates all files with a specific extension, excluding specified folders.
- """
- if not extension.startswith('.'):
- print("Error: Extension must start with a dot (e.g., '.txt').", file=sys.stderr)
- return []
-
- # If project_root isn't specified, assume it's the same as the search root.
- if project_root is None:
- project_root = root_dir
-
- found_files = []
- for root, dirs, files in os.walk(root_dir):
- # Prune ignored directories to prevent descending into them
- dirs[:] = [d for d in dirs if not _is_path_ignored(os.path.join(root, d), project_root, ignored_folders)]
-
- for file in files:
- if file.endswith(extension):
- full_path = os.path.join(root, file)
- if not _is_path_ignored(full_path, project_root, ignored_folders):
- found_files.append(full_path)
- return found_files
- def replicate_directory_structure(source_root, target_root, ignored_folders=None, project_root=None):
- """
- Copies a directory tree, excluding specified folders.
- """
- source_root_path = Path(source_root)
- target_root_path = Path(target_root)
- if not source_root_path.is_dir():
- print(f"Error: Source path '{source_root_path}' is not a valid directory.", file=sys.stderr)
- return
- if project_root is None:
- project_root = source_root
- for dirpath, dirnames, _ in os.walk(source_root):
- # Prune ignored directories
- dirnames[:] = [d for d in dirnames if not _is_path_ignored(os.path.join(dirpath, d), project_root, ignored_folders)]
- relative_path = Path(dirpath).relative_to(source_root_path)
- target_path = target_root_path / relative_path
- target_path.mkdir(parents=True, exist_ok=True)
- def create_guid_to_path_map(root_dir, ignored_folders=None):
- """
- Creates a dictionary mapping GUIDs to their corresponding asset file paths,
- respecting an ignore list.
- """
- guid_map = {}
- # Define scan directories relative to the project root
- relative_scan_dirs = ['Assets', 'Packages', 'Library/PackageCache']
-
- for rel_dir in relative_scan_dirs:
- scan_dir = os.path.join(root_dir, rel_dir)
- if not os.path.isdir(scan_dir):
- continue
-
- meta_files = find_files_by_extension(scan_dir, '.meta', ignored_folders, project_root=root_dir)
- for meta_file_path in meta_files:
- asset_path = meta_file_path[:-5]
- guid = None
- is_folder = False
- try:
- with open(meta_file_path, 'r', encoding='utf-8') as f:
- for line in f:
- stripped_line = line.strip()
- if stripped_line.startswith('guid:'):
- guid = stripped_line.split(':')[1].strip()
- if stripped_line == 'folderAsset: yes':
- is_folder = True
- break
-
- if is_folder:
- continue
- if guid and guid not in guid_map:
- # Store path relative to the root_dir for consistency
- guid_map[guid] = Path(asset_path).relative_to(root_dir).as_posix()
- except Exception as e:
- print(f"Warning: Could not process meta file {meta_file_path}. {e}", file=sys.stderr)
- return guid_map
- if __name__ == '__main__':
- # Example usage for testing the module directly.
- import shutil
- test_root = Path('./tmp_test_root')
- test_source_dir = test_root / 'Assets'
- test_target_dir = Path('./tmp_target_for_testing')
- ignored_list = ['Assets/ThirdParty']
- try:
- print("Setting up test directory structure...")
- (test_source_dir / 'scenes').mkdir(parents=True, exist_ok=True)
- (test_source_dir / 'prefabs').mkdir(parents=True, exist_ok=True)
- (test_source_dir / 'ThirdParty' / 'ignored').mkdir(parents=True, exist_ok=True)
- (test_source_dir / 'scenes' / 'level1.unity').touch()
- (test_source_dir / 'prefabs' / 'player.prefab').touch()
- (test_source_dir / 'ThirdParty' / 'ignored' / 'plugin.cs').touch()
-
- print(f"\n--- Testing find_files_by_extension with ignore list: {ignored_list} ---")
-
- # Test finding files (should ignore the .cs file)
- all_files = find_files_by_extension(str(test_source_dir), '.cs', ignored_folders=ignored_list, project_root=test_root)
- print(f"Found .cs files: {all_files}")
- assert len(all_files) == 0
- unity_files = find_files_by_extension(str(test_source_dir), '.unity', ignored_folders=ignored_list, project_root=test_root)
- print(f"Found .unity files: {unity_files}")
- assert len(unity_files) == 1
- print("\n--- Testing replicate_directory_structure with ignore list ---")
- replicate_directory_structure(str(test_source_dir), str(test_target_dir), ignored_folders=ignored_list, project_root=test_root)
-
- print("Checking replicated structure:")
- assert (test_target_dir / 'scenes').is_dir()
- assert not (test_target_dir / 'ThirdParty').exists()
- print("Replicated structure seems correct (ignored folder was skipped).")
- finally:
- if test_root.exists():
- shutil.rmtree(test_root)
- if test_target_dir.exists():
- shutil.rmtree(test_target_dir)
- print("\nCleaned up test directories.")
|