Skip to content

Commit 3ee5d2e

Browse files
committed
extracted code to functions in installer.py
1 parent 840e72d commit 3ee5d2e

File tree

1 file changed

+82
-101
lines changed

1 file changed

+82
-101
lines changed

installer.py

Lines changed: 82 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,61 @@
66
import sys
77
import threading
88
import time
9-
109
from helper.config_operations import get_library_path, get_debug_mode
1110
from helper.file_operations import create_temp_folder, delete_temp_folder, create_logger
1211
from patoolib.util import PatoolError
1312
import content_database
1413
import patches
1514

15+
# Create a logger instance
1616
logger = create_logger()
1717

18-
TEMP_FOLDER = pathlib.Path("temp") # Temporary folder for extraction
19-
20-
21-
lock = threading.Lock()
18+
# Path to the temporary extraction folder
19+
TEMP_FOLDER = pathlib.Path("temp")
2220

21+
# Folders to target during extraction
2322
TARGET_FOLDERS = [
24-
"aniBlocks", "data", "Environments", "Light Presets", "People",
25-
"Props", "ReadMe's", "Render Presets", "Render Settings", "Runtime",
26-
"Scenes", "Scripts", "Shader Presets", "Cameras", "Documentation"
23+
"aniBlocks", "data", "Environments", "Light Presets", "People", "Props",
24+
"ReadMe's", "Render Presets", "Render Settings", "Runtime", "Scenes",
25+
"Scripts", "Shader Presets", "Cameras", "Documentation"
2726
]
2827

28+
# Determine base path based on execution context
2929
if getattr(sys, "frozen", False):
3030
BASE_PATH = pathlib.Path(sys._MEIPASS)
3131
else:
3232
BASE_PATH = pathlib.Path(__file__).parent
3333

34+
# Path to the 7z executable
3435
SEVEN_ZIP_PATH = BASE_PATH / "7z/7z.exe"
3536

37+
# Create a threading lock
38+
lock = threading.Lock()
39+
3640

3741
def get_relative_path(full_path: str) -> str:
3842
"""
39-
Extract the relative path starting from the first occurrence of a target folder.
43+
Get the relative path based on target folders.
44+
If the path contains a target folder, return the sub-path starting
45+
from the target folder.
4046
"""
4147
pattern = r'|'.join([re.escape(folder) for folder in TARGET_FOLDERS])
4248
match = re.search(pattern, full_path)
4349
return full_path[match.start():] if match else full_path
4450

51+
4552
def clean_temp_folder() -> None:
4653
"""
47-
Clean and recreate the temporary folder.
54+
Clean the temporary folder by removing its contents.
4855
"""
4956
if TEMP_FOLDER.exists():
5057
shutil.rmtree(TEMP_FOLDER)
5158
TEMP_FOLDER.mkdir(parents=True, exist_ok=True)
5259

60+
5361
def extract_archive(item_path: pathlib.Path, is_debug_mode: bool) -> bool:
5462
"""
55-
Extract the archive to the temporary folder.
63+
Extract an archive into the temporary folder.
5664
"""
5765
base_item_name = item_path.name
5866
if base_item_name.lower().endswith(('.zip', '.rar', '7z', '.tar')):
@@ -73,26 +81,22 @@ def extract_archive(item_path: pathlib.Path, is_debug_mode: bool) -> bool:
7381
return False
7482
return False
7583

84+
7685
def clean_folder(folder_path: pathlib.Path) -> None:
7786
"""
78-
Remove all files that are not part of the target folders.
87+
Remove all files in the specified folder.
7988
"""
8089
for item in folder_path.iterdir():
8190
if item.is_file():
8291
item.unlink()
8392

93+
8494
def add_to_database(root_path: pathlib.Path, item: pathlib.Path) -> bool:
8595
"""
86-
Add the archive's content to the database.
96+
Add the extracted files to the content database.
8797
"""
8898
archive_name = item.stem.split(".")[0]
89-
file_list = []
90-
91-
# Collect all files in the directory
92-
for file_path in root_path.rglob("*"):
93-
if file_path.is_file():
94-
relative_path = get_relative_path(str(file_path))
95-
file_list.append(relative_path)
99+
file_list = [get_relative_path(str(file_path)) for file_path in root_path.rglob("*") if file_path.is_file()]
96100

97101
if content_database.does_archive_exist(archive_name, file_list):
98102
logger.info(f"Archive '{archive_name}' already exists in the database.")
@@ -104,89 +108,71 @@ def add_to_database(root_path: pathlib.Path, item: pathlib.Path) -> bool:
104108
return False
105109

106110

107-
# Searching the content of extracted archive for target folders
108-
def traverse_directory(
109-
folder_path: pathlib.Path,
110-
current_item: pathlib.Path,
111-
progressbar,
112-
is_debug_mode: bool,
113-
) -> bool:
111+
def handle_nested_archives(root_path, files, is_debug_mode):
114112
"""
115-
Process a directory, search for nested archives, and add valid content to the library.
116-
117-
Args:
118-
folder_path (pathlib.Path): The path of the folder to process.
119-
current_item (pathlib.Path): The current archive being processed.
120-
progressbar: A GUI progress bar object to track progress.
121-
is_debug_mode (bool): Whether debug mode is enabled for verbose logs.
122-
123-
Returns:
124-
bool: True if the content was successfully added to the library, False otherwise.
113+
Handle and extract nested archives within the main archive.
125114
"""
126115
archive_extracted = False
127-
manifest_exists = False
116+
for file in files:
117+
file_path = root_path / file
118+
if file.lower().endswith(('.zip', '.rar', '7z', '.tar')):
119+
logger.info(f"Extracting nested archive: {file}")
120+
try:
121+
verbosity = 2 if is_debug_mode else -1
122+
patoolib.extract_archive(
123+
str(file_path),
124+
outdir=str(root_path),
125+
verbosity=verbosity,
126+
interactive=False,
127+
program=str(SEVEN_ZIP_PATH),
128+
)
129+
time.sleep(0.5)
130+
file_path.unlink() # Delete the nested archive after extraction
131+
archive_extracted = True
132+
except PatoolError as e:
133+
logger.error(f"Failed to extract nested archive {file}: {e}")
134+
return archive_extracted
135+
136+
137+
def process_manifest_and_target_folders(root_path, dirs, files, progressbar, current_item):
138+
"""
139+
Check for manifest files and target folders, and process them accordingly.
140+
"""
141+
manifest_exists = any(file.lower().endswith("manifest.dsx") for file in files)
142+
143+
if manifest_exists or any(target in dirs for target in TARGET_FOLDERS):
144+
for folder in dirs:
145+
if manifest_exists and folder.lower().startswith("content"):
146+
content_path = root_path / folder
147+
clean_folder(content_path)
148+
if add_to_database(content_path, current_item):
149+
return False
150+
shutil.copytree(content_path, get_library_path(), dirs_exist_ok=True)
151+
return True
152+
153+
if any(target.lower() == folder.lower() for target in TARGET_FOLDERS):
154+
clean_folder(root_path)
155+
if add_to_database(root_path, current_item):
156+
return False
157+
shutil.copytree(root_path, get_library_path(), dirs_exist_ok=True)
158+
return True
159+
return False
128160

129-
# Traverse the directory structure
161+
162+
def traverse_directory(folder_path: pathlib.Path, current_item: pathlib.Path, progressbar, is_debug_mode: bool):
163+
"""
164+
Traverse the directory structure and handle nested archives and target folders.
165+
"""
130166
for root, dirs, files in folder_path.walk():
131167
root_path = pathlib.Path(root)
132-
133-
for file in files:
134-
file_path = root_path / file
135-
136-
# Handle nested archives
137-
if file.lower().endswith(('.zip', '.rar', '7z', '.tar')):
138-
logger.info(f"Extracting nested archive: {file}")
139-
try:
140-
verbosity = 2 if is_debug_mode else -1
141-
patoolib.extract_archive(
142-
str(file_path),
143-
outdir=str(root_path),
144-
verbosity=verbosity,
145-
interactive=False,
146-
program=str(SEVEN_ZIP_PATH),
147-
)
148-
time.sleep(0.5)
149-
file_path.unlink() # Delete the nested archive after extraction
150-
archive_extracted = True
151-
except PatoolError as e:
152-
logger.error(f"Failed to extract nested archive {file}: {e}")
153-
154-
# Check for manifest files
155-
if file.lower().endswith("manifest.dsx"):
156-
manifest_exists = True
157-
158-
progressbar.set(progressbar.get() + 0.1)
159-
160-
# If a nested archive was extracted, restart traversal
161-
if archive_extracted:
162-
progressbar.set(progressbar.get() + 0.1)
163-
return traverse_directory(folder_path, current_item, progressbar, is_debug_mode, is_nested_archive=True)
164-
165-
if manifest_exists:
166-
for folder in dirs:
167-
if folder.lower().startswith("content"):
168-
content_path = root_path / folder
169-
progressbar.set(0.9)
170-
clean_folder(content_path)
171-
if add_to_database(content_path, current_item):
172-
return False
173-
shutil.copytree(content_path, get_library_path(), dirs_exist_ok=True)
174-
return True
175-
176-
if any(target in dirs for target in TARGET_FOLDERS):
177-
progressbar.set(0.9)
178-
clean_folder(root_path)
179-
if add_to_database(root_path, current_item):
180-
return False
181-
shutil.copytree(root_path, get_library_path(), dirs_exist_ok=True)
168+
if handle_nested_archives(root_path, files, is_debug_mode):
169+
return traverse_directory(folder_path, current_item, progressbar, is_debug_mode)
170+
if process_manifest_and_target_folders(root_path, dirs, files, progressbar, current_item):
182171
return True
183-
184172
return False
185173

186174

187-
def start_installer_gui(
188-
file_path: str, progressbar, is_delete_archive: bool = False
189-
) -> bool:
175+
def start_installer_gui(file_path: str, progressbar, is_delete_archive: bool = False) -> bool:
190176
"""
191177
Main function to handle the installation process via the GUI.
192178
@@ -199,39 +185,34 @@ def start_installer_gui(
199185
bool: True if the archive was successfully imported, False otherwise.
200186
"""
201187
is_archive_imported = False
202-
file_path = pathlib.Path(file_path) # Convert the input string to a pathlib.Path object
203-
204-
with lock: # Ensure thread safety
188+
file_path = pathlib.Path(file_path)
189+
with lock:
205190
logger.info(f"Installing {file_path}")
206191
create_temp_folder()
207192
clean_temp_folder()
208193
progressbar.set(0.1)
209194

210-
# Step 1: Extract the archive
211195
if not extract_archive(file_path, get_debug_mode()):
212196
clean_temp_folder()
213197
return is_archive_imported
214198

215199
progressbar.set(0.4)
216200

217-
# Step 2: Traverse the extracted directory
218201
if traverse_directory(TEMP_FOLDER, file_path, progressbar, get_debug_mode()):
219202
is_archive_imported = True
220203
logger.info(f"Successfully imported: {file_path}")
221204
else:
222205
is_archive_imported = False
223206
logger.warning(f"Failed to import {file_path}. Invalid folder structure or asset already exists.")
224207

225-
# Cleanup
226208
clean_temp_folder()
227209
delete_temp_folder()
228210

229-
# Step 3: Delete the original archive if requested
230211
if is_delete_archive:
231212
try:
232213
file_path.unlink()
233214
logger.info(f"Deleted archive: {file_path}")
234215
except Exception as e:
235216
logger.error(f"Failed to delete archive {file_path}: {e}")
236217

237-
return is_archive_imported
218+
return is_archive_imported

0 commit comments

Comments
 (0)