feat(core): rewrite installer with modular config, dynamic drive resolver, and clean orchestration
This commit is contained in:
165
main.py
165
main.py
@@ -1,27 +1,148 @@
|
||||
import os
|
||||
"""
|
||||
Main Orchestrator for Acc Installer.
|
||||
Executes directory setup, file copy, archive extraction, and automated installation.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
import subprocess
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MODULE_DIR = os.path.join(BASE_DIR, "module")
|
||||
from module.config import InstallerConfig, detect_target_drive
|
||||
from module.downloader_copier import setup_directories_and_copy
|
||||
from module.extract_acc import extract_acc_archive
|
||||
from module.install_novindesk import install_novindesk
|
||||
|
||||
scripts = [
|
||||
"downloader_copier.py",
|
||||
"extract_acc.py",
|
||||
"install_novindesk.py"
|
||||
]
|
||||
|
||||
for script in scripts:
|
||||
script_path = os.path.join(MODULE_DIR, script)
|
||||
print(f"[+] Running {script}...")
|
||||
result = subprocess.run([sys.executable, script_path], capture_output=True, text=True)
|
||||
def setup_logger(verbose: bool = False) -> logging.Logger:
|
||||
level = logging.DEBUG if verbose else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=level,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
datefmt="%H:%M:%S"
|
||||
)
|
||||
return logging.getLogger("acc_installer")
|
||||
|
||||
if result.returncode == 0:
|
||||
print(f"[+] {script} executed successfully.\n")
|
||||
else:
|
||||
print(f"[-] Error running {script}:")
|
||||
if result.stdout:
|
||||
print(result.stdout)
|
||||
if result.stderr:
|
||||
print(result.stderr)
|
||||
break
|
||||
|
||||
def parse_arguments() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="NovinPardaz Acc Installer - Automated Setup Pipeline",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source",
|
||||
type=str,
|
||||
default=r"C:\SoftwareNP",
|
||||
help="Source directory containing installation archives"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--drive",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Target drive for installation (e.g. 'D:\\'). Auto-detected if not specified."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Simulate execution without modifying files or launching processes"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-acc",
|
||||
action="store_true",
|
||||
help="Skip extraction of NovinAcc archive"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-desk",
|
||||
action="store_true",
|
||||
help="Skip installation of NovinDesk"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-ui",
|
||||
action="store_true",
|
||||
help="Disable automatic UI interaction during NovinDesk installation"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
"-v",
|
||||
action="store_true",
|
||||
help="Enable detailed debug logging"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def run_pipeline(config: InstallerConfig,
|
||||
skip_acc: bool = False,
|
||||
skip_desk: bool = False,
|
||||
auto_ui: bool = True) -> bool:
|
||||
"""
|
||||
Executes the installer pipeline steps sequentially.
|
||||
"""
|
||||
start_time = time.time()
|
||||
print("=" * 60)
|
||||
print(" NovinPardaz Acc Installer Pipeline ")
|
||||
print("=" * 60)
|
||||
print(f" Source Directory : {config.source_dir}")
|
||||
print(f" Target Drive : {config.target_drive}")
|
||||
print(f" Target Base Dir : {config.base_dir}")
|
||||
print(f" Dry Run Mode : {config.dry_run}")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
# Step 1: Directory Setup & Software Copy
|
||||
print("\n[Step 1/3] Setting up directories and copying software files...")
|
||||
setup_directories_and_copy(config)
|
||||
print("[+] Step 1 completed successfully.")
|
||||
|
||||
# Step 2: Extract NovinAcc Archive
|
||||
if not skip_acc:
|
||||
print("\n[Step 2/3] Extracting NovinAcc accounting archive...")
|
||||
extract_acc_archive(config)
|
||||
print("[+] Step 2 completed successfully.")
|
||||
else:
|
||||
print("\n[Step 2/3] Skipped NovinAcc extraction (--skip-acc specified).")
|
||||
|
||||
# Step 3: Install NovinDesk
|
||||
if not skip_desk:
|
||||
print("\n[Step 3/3] Extracting and launching NovinDesk installer...")
|
||||
install_novindesk(config, auto_ui=auto_ui)
|
||||
print("[+] Step 3 completed successfully.")
|
||||
else:
|
||||
print("\n[Step 3/3] Skipped NovinDesk installation (--skip-desk specified).")
|
||||
|
||||
elapsed = time.time() - start_time
|
||||
print("\n" + "=" * 60)
|
||||
print(f"[SUCCESS] All installation steps completed in {elapsed:.2f} seconds.")
|
||||
print("=" * 60)
|
||||
return True
|
||||
|
||||
except Exception as exc:
|
||||
elapsed = time.time() - start_time
|
||||
print(f"\n[-] Installation pipeline failed after {elapsed:.2f} seconds!")
|
||||
print(f"[-] Error: {exc}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_arguments()
|
||||
setup_logger(args.verbose)
|
||||
|
||||
target_drive = args.drive if args.drive else detect_target_drive()
|
||||
config = InstallerConfig(
|
||||
source_dir=args.source,
|
||||
target_drive=target_drive,
|
||||
dry_run=args.dry_run
|
||||
)
|
||||
|
||||
success = run_pipeline(
|
||||
config=config,
|
||||
skip_acc=args.skip_acc,
|
||||
skip_desk=args.skip_desk,
|
||||
auto_ui=not args.no_ui
|
||||
)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1 +1,16 @@
|
||||
# Module package
|
||||
"""
|
||||
NovinPardaz Acc Installer Package.
|
||||
"""
|
||||
|
||||
from module.config import InstallerConfig, detect_target_drive
|
||||
from module.downloader_copier import setup_directories_and_copy
|
||||
from module.extract_acc import extract_acc_archive
|
||||
from module.install_novindesk import install_novindesk
|
||||
|
||||
__all__ = [
|
||||
"InstallerConfig",
|
||||
"detect_target_drive",
|
||||
"setup_directories_and_copy",
|
||||
"extract_acc_archive",
|
||||
"install_novindesk",
|
||||
]
|
||||
|
||||
64
module/config.py
Normal file
64
module/config.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
Configuration and environment resolution for Acc Installer.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
logger = logging.getLogger("acc_installer")
|
||||
|
||||
|
||||
def detect_target_drive(candidates: Optional[List[str]] = None) -> str:
|
||||
"""
|
||||
Find the first available non-system drive on Windows.
|
||||
Falls back to 'C:\\' if no secondary drive is found.
|
||||
"""
|
||||
if candidates is None:
|
||||
candidates = ["D", "E", "F", "G", "H"]
|
||||
|
||||
for letter in candidates:
|
||||
drive_path = f"{letter}:\\"
|
||||
if os.path.exists(drive_path):
|
||||
logger.info("Found candidate drive: %s", drive_path)
|
||||
return drive_path
|
||||
|
||||
logger.warning("No secondary drive found in candidates. Falling back to C:\\")
|
||||
return "C:\\"
|
||||
|
||||
|
||||
@dataclass
|
||||
class InstallerConfig:
|
||||
"""
|
||||
Centralized configuration holding paths and operational flags for the installer.
|
||||
"""
|
||||
source_dir: Path = field(default_factory=lambda: Path(r"C:\SoftwareNP"))
|
||||
target_drive: str = field(default_factory=detect_target_drive)
|
||||
dry_run: bool = False
|
||||
|
||||
# Calculated paths
|
||||
base_dir: Path = field(init=False)
|
||||
soft_dir: Path = field(init=False)
|
||||
acc_dir: Path = field(init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
# Normalize target drive
|
||||
if not self.target_drive.endswith("\\") and not self.target_drive.endswith("/"):
|
||||
self.target_drive = f"{self.target_drive}\\"
|
||||
|
||||
drive_path = Path(self.target_drive)
|
||||
self.base_dir = drive_path / "NovinPardazOne"
|
||||
self.soft_dir = self.base_dir / "NovinSoft"
|
||||
self.acc_dir = self.base_dir / "NovinAcc"
|
||||
|
||||
def ensure_directories(self) -> None:
|
||||
"""Create necessary target directories if they do not exist."""
|
||||
if self.dry_run:
|
||||
logger.info("[DRY-RUN] Would create: %s and %s", self.soft_dir, self.acc_dir)
|
||||
return
|
||||
|
||||
self.soft_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.acc_dir.mkdir(parents=True, exist_ok=True)
|
||||
logger.debug("Ensured directories at %s and %s", self.soft_dir, self.acc_dir)
|
||||
@@ -1,63 +1,65 @@
|
||||
"""
|
||||
Directory setup and software file copying module.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from typing import Optional
|
||||
|
||||
def get_non_c_drive() -> str:
|
||||
from module.config import InstallerConfig, detect_target_drive
|
||||
|
||||
logger = logging.getLogger("acc_installer")
|
||||
|
||||
|
||||
def setup_directories_and_copy(config: Optional[InstallerConfig] = None) -> Path:
|
||||
"""
|
||||
Find the first available non-C drive on the target system.
|
||||
Create directories on the target drive and copy software packages from source.
|
||||
"""
|
||||
possible_drives = [f"{letter}:\\" for letter in "DEFGH"]
|
||||
for drive in possible_drives:
|
||||
if os.path.exists(drive):
|
||||
return drive
|
||||
return r"C:\\"
|
||||
if config is None:
|
||||
config = InstallerConfig()
|
||||
|
||||
def setup_directories_and_copy(source_dir: str = r"C:\SoftwareNP",
|
||||
target_drive: str = None) -> str:
|
||||
"""
|
||||
Create directories on a non-C drive and copy files from source to NovinSoft.
|
||||
"""
|
||||
if not target_drive:
|
||||
base_drive = get_non_c_drive()
|
||||
else:
|
||||
base_drive = target_drive
|
||||
print(f"[+] Selected target drive: {config.target_drive}")
|
||||
print(f"[+] Target base directory: {config.base_dir}")
|
||||
|
||||
# Base target directory set to NovinPardazOne
|
||||
base_target_dir = os.path.join(base_drive, "NovinPardazOne")
|
||||
acc_dir = os.path.join(base_target_dir, "NovinAcc")
|
||||
soft_dir = os.path.join(base_target_dir, "NovinSoft")
|
||||
# Ensure source directory exists
|
||||
source_dir = Path(config.source_dir)
|
||||
if not source_dir.exists():
|
||||
raise FileNotFoundError(f"Source directory does not exist: {source_dir}")
|
||||
|
||||
print(f"[+] Selected target drive: {base_drive}")
|
||||
print(f"[+] Creating directory structure at {base_target_dir} ...")
|
||||
# Create destination directories
|
||||
config.ensure_directories()
|
||||
print(f" [+] Target directories ready at {config.soft_dir}")
|
||||
|
||||
# Create NovinAcc and NovinSoft directories
|
||||
os.makedirs(acc_dir, exist_ok=True)
|
||||
os.makedirs(soft_dir, exist_ok=True)
|
||||
print(" [+] NovinAcc and NovinSoft directories created successfully.")
|
||||
print(f"[+] Copying files from {source_dir} to {config.soft_dir} ...")
|
||||
|
||||
# Copy contents of source directory to NovinSoft
|
||||
if os.path.exists(source_dir):
|
||||
print(f"[+] Copying files from {source_dir} to {soft_dir} ...")
|
||||
if config.dry_run:
|
||||
items = list(source_dir.iterdir())
|
||||
print(f" [DRY-RUN] Would copy {len(items)} items from {source_dir} to {config.soft_dir}")
|
||||
return config.soft_dir
|
||||
|
||||
for item in os.listdir(source_dir):
|
||||
s = os.path.join(source_dir, item)
|
||||
d = os.path.join(soft_dir, item)
|
||||
copied_count = 0
|
||||
for item in source_dir.iterdir():
|
||||
dest = config.soft_dir / item.name
|
||||
if item.is_dir():
|
||||
shutil.copytree(item, dest, dirs_exist_ok=True)
|
||||
else:
|
||||
shutil.copy2(item, dest)
|
||||
copied_count += 1
|
||||
|
||||
if os.path.isdir(s):
|
||||
shutil.copytree(s, d, dirs_exist_ok=True)
|
||||
else:
|
||||
shutil.copy2(s, d)
|
||||
print(f" [+] {copied_count} file(s)/folder(s) copied successfully to {config.soft_dir}.")
|
||||
return config.soft_dir
|
||||
|
||||
print(f" [+] All files copied successfully to {soft_dir}.")
|
||||
return soft_dir
|
||||
else:
|
||||
raise FileNotFoundError(f"[-] Source directory not found at {source_dir}!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system("chcp 65001 > nul")
|
||||
print("[+] Testing directory creation and software copy module ...")
|
||||
|
||||
import sys
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
print("[*] Running directory setup and copier module standalone ...")
|
||||
try:
|
||||
target_path = setup_directories_and_copy(target_drive=r"D:\\")
|
||||
print(f"\n[+] Operation completed successfully. Software path: {target_path}")
|
||||
cfg = InstallerConfig(target_drive=detect_target_drive())
|
||||
setup_directories_and_copy(cfg)
|
||||
print("[+] Directory copier module completed successfully.")
|
||||
except Exception as e:
|
||||
print(f"\n[-] Error: {e}")
|
||||
print(f"[-] Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,50 +1,75 @@
|
||||
"""
|
||||
Archive extractor module for NovinAcc accounting software.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from typing import Optional
|
||||
import zipfile
|
||||
|
||||
def extract_acc_archive(base_drive: str = r"D:\\") -> str:
|
||||
# Base directory set to NovinPardazOne
|
||||
base_dir = os.path.join(base_drive, "NovinPardazOne")
|
||||
soft_dir = os.path.join(base_dir, "NovinSoft")
|
||||
acc_dir = os.path.join(base_dir, "NovinAcc")
|
||||
from module.config import InstallerConfig, detect_target_drive
|
||||
|
||||
target_zip_name = "NovinAcc.zip"
|
||||
source_zip_path = os.path.join(soft_dir, target_zip_name)
|
||||
target_zip_path = os.path.join(acc_dir, target_zip_name)
|
||||
logger = logging.getLogger("acc_installer")
|
||||
|
||||
# 1. Check if NovinSoft directory exists
|
||||
if not os.path.exists(soft_dir):
|
||||
raise FileNotFoundError(f"[-] Directory not found: {soft_dir}")
|
||||
|
||||
# 2. Check if zip file exists
|
||||
if not os.path.exists(source_zip_path):
|
||||
raise FileNotFoundError(f"[-] File {target_zip_name} was not found in {soft_dir}!")
|
||||
def extract_acc_archive(config: Optional[InstallerConfig] = None,
|
||||
archive_name: str = "NovinAcc.zip") -> Path:
|
||||
"""
|
||||
Locates NovinAcc archive in NovinSoft, moves it to NovinAcc, and extracts its contents.
|
||||
"""
|
||||
if config is None:
|
||||
config = InstallerConfig()
|
||||
|
||||
# 3. Create NovinAcc directory if it doesn't exist
|
||||
os.makedirs(acc_dir, exist_ok=True)
|
||||
source_zip = config.soft_dir / archive_name
|
||||
target_zip = config.acc_dir / archive_name
|
||||
|
||||
# 4. Move zip file to NovinAcc
|
||||
print(f"[+] Moving {target_zip_name} to NovinAcc directory...")
|
||||
shutil.move(source_zip_path, target_zip_path)
|
||||
print(" [+] Zip file moved successfully.")
|
||||
config.ensure_directories()
|
||||
|
||||
# 5. Extract archive
|
||||
print(f"[+] Extracting archive to {acc_dir}...")
|
||||
with zipfile.ZipFile(target_zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(acc_dir)
|
||||
print(" [+] All files extracted successfully.")
|
||||
if config.dry_run:
|
||||
print(f" [DRY-RUN] Would locate {archive_name} in {config.soft_dir}, move to {config.acc_dir} and extract.")
|
||||
return config.acc_dir
|
||||
|
||||
# 6. Remove temporary zip file
|
||||
if os.path.exists(target_zip_path):
|
||||
os.remove(target_zip_path)
|
||||
print(" [+] Temporary zip file deleted.")
|
||||
# Check if archive exists in soft_dir or already in acc_dir
|
||||
archive_to_extract = None
|
||||
if source_zip.exists():
|
||||
archive_to_extract = source_zip
|
||||
elif target_zip.exists():
|
||||
archive_to_extract = target_zip
|
||||
else:
|
||||
raise FileNotFoundError(
|
||||
f"Archive '{archive_name}' was not found in either {config.soft_dir} or {config.acc_dir}!"
|
||||
)
|
||||
|
||||
# Move archive to target NovinAcc directory if not already there
|
||||
if archive_to_extract != target_zip:
|
||||
print(f"[+] Moving {archive_name} to NovinAcc directory...")
|
||||
shutil.move(str(source_zip), str(target_zip))
|
||||
print(" [+] Zip archive moved successfully.")
|
||||
|
||||
# Extract archive
|
||||
print(f"[+] Extracting {archive_name} into {config.acc_dir} ...")
|
||||
with zipfile.ZipFile(target_zip, 'r') as zip_ref:
|
||||
zip_ref.extractall(config.acc_dir)
|
||||
print(" [+] All archive files extracted successfully.")
|
||||
|
||||
# Remove temporary zip file
|
||||
if target_zip.exists():
|
||||
target_zip.unlink()
|
||||
print(" [+] Temporary zip archive cleaned up.")
|
||||
|
||||
return config.acc_dir
|
||||
|
||||
return acc_dir
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system("chcp 65001 > nul")
|
||||
print("[+] Running move and extract module ...")
|
||||
import sys
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
print("[*] Running NovinAcc archive extractor standalone ...")
|
||||
try:
|
||||
extract_acc_archive(base_drive=r"D:\\")
|
||||
cfg = InstallerConfig(target_drive=detect_target_drive())
|
||||
extract_acc_archive(cfg)
|
||||
print("[+] NovinAcc extraction completed successfully.")
|
||||
except Exception as e:
|
||||
print(f"[-] Error: {e}")
|
||||
print(f"[-] Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,71 +1,107 @@
|
||||
"""
|
||||
Extractor and automated installer runner for NovinDesk.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import time
|
||||
from typing import Optional
|
||||
import zipfile
|
||||
|
||||
def install_novindesk(base_drive: str = r"D:\\") -> str:
|
||||
from module.config import InstallerConfig, detect_target_drive
|
||||
|
||||
logger = logging.getLogger("acc_installer")
|
||||
|
||||
|
||||
def automate_installer_dialog() -> bool:
|
||||
"""
|
||||
Extract and automatically install NovinDesk by navigating the installer UI.
|
||||
Automate UI dialog clicks for silent installation using pyautogui.
|
||||
"""
|
||||
base_dir = os.path.join(base_drive, "NovinPardazOne")
|
||||
soft_dir = os.path.join(base_dir, "NovinSoft")
|
||||
|
||||
zip_filename = "NovinDesk.zip"
|
||||
source_zip_path = os.path.join(soft_dir, zip_filename)
|
||||
extract_target_dir = os.path.join(soft_dir, "NovinDesk")
|
||||
|
||||
if not os.path.exists(source_zip_path):
|
||||
raise FileNotFoundError(f"[-] File {zip_filename} was not found in {soft_dir}!")
|
||||
|
||||
os.makedirs(extract_target_dir, exist_ok=True)
|
||||
|
||||
print(f"[+] Extracting {zip_filename} ...")
|
||||
with zipfile.ZipFile(source_zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_target_dir)
|
||||
print(" [+] Extraction completed successfully.")
|
||||
|
||||
exe_file = None
|
||||
for root, dirs, files in os.walk(extract_target_dir):
|
||||
for file in files:
|
||||
if file.lower().endswith(".exe"):
|
||||
exe_file = os.path.join(root, file)
|
||||
break
|
||||
|
||||
if not exe_file:
|
||||
raise FileNotFoundError("[-] No executable file (.exe) found!")
|
||||
|
||||
print(f"[+] Launching installer {os.path.basename(exe_file)} ...")
|
||||
|
||||
# Launch application for installation
|
||||
subprocess.Popen([exe_file, "--install"])
|
||||
|
||||
# Wait 5 seconds for the window to fully load
|
||||
time.sleep(5)
|
||||
|
||||
try:
|
||||
import pyautogui
|
||||
import pyautogui # type: ignore
|
||||
|
||||
# 1. Close any secondary/side dialogs
|
||||
pyautogui.press('escape')
|
||||
time.sleep(0.5)
|
||||
|
||||
# 2. Press Tab 4 times to navigate directly to the 'Accept & Install' button
|
||||
# 2. Press Tab 4 times to navigate directly to 'Accept & Install'
|
||||
for _ in range(4):
|
||||
pyautogui.press('tab')
|
||||
time.sleep(0.2)
|
||||
|
||||
# 3. Press Enter on the install button
|
||||
pyautogui.press('enter')
|
||||
print(" [+] Confirmation sent and automated installation started.")
|
||||
print(" [+] Sent automated UI confirmation successfully.")
|
||||
return True
|
||||
except ImportError:
|
||||
print(" [!] Warning: 'pyautogui' is not installed. Skipping UI automation.")
|
||||
return False
|
||||
except Exception as err:
|
||||
print(f" [-] Automation error: {err}")
|
||||
print(f" [-] UI Automation error: {err}")
|
||||
return False
|
||||
|
||||
|
||||
def install_novindesk(config: Optional[InstallerConfig] = None,
|
||||
archive_name: str = "NovinDesk.zip",
|
||||
auto_ui: bool = True) -> Path:
|
||||
"""
|
||||
Extracts NovinDesk archive, finds the installer executable, and runs installation.
|
||||
"""
|
||||
if config is None:
|
||||
config = InstallerConfig()
|
||||
|
||||
source_zip = config.soft_dir / archive_name
|
||||
extract_target_dir = config.soft_dir / "NovinDesk"
|
||||
|
||||
if config.dry_run:
|
||||
print(f" [DRY-RUN] Would locate {archive_name}, extract into {extract_target_dir}, and launch installer.")
|
||||
return extract_target_dir
|
||||
|
||||
if not source_zip.exists() and not extract_target_dir.exists():
|
||||
raise FileNotFoundError(f"Neither '{source_zip}' nor '{extract_target_dir}' exists!")
|
||||
|
||||
# Extract archive if needed
|
||||
if source_zip.exists():
|
||||
extract_target_dir.mkdir(parents=True, exist_ok=True)
|
||||
print(f"[+] Extracting {archive_name} into {extract_target_dir} ...")
|
||||
with zipfile.ZipFile(source_zip, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_target_dir)
|
||||
print(" [+] Extraction completed successfully.")
|
||||
|
||||
# Locate executable
|
||||
exe_file = None
|
||||
for root, _, files in os.walk(extract_target_dir):
|
||||
for file in files:
|
||||
if file.lower().endswith(".exe"):
|
||||
exe_file = Path(root) / file
|
||||
break
|
||||
if exe_file:
|
||||
break
|
||||
|
||||
if not exe_file:
|
||||
raise FileNotFoundError(f"No executable (.exe) found in {extract_target_dir}!")
|
||||
|
||||
print(f"[+] Launching installer {exe_file.name} ...")
|
||||
subprocess.Popen([str(exe_file), "--install"])
|
||||
|
||||
if auto_ui:
|
||||
print(" [*] Waiting 5 seconds for installer window to initialize...")
|
||||
time.sleep(5)
|
||||
automate_installer_dialog()
|
||||
|
||||
return exe_file
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system("chcp 65001 > nul")
|
||||
print("[+] Running NovinDesk installation module ...")
|
||||
import sys
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
print("[*] Running NovinDesk installation module standalone ...")
|
||||
try:
|
||||
install_novindesk(base_drive=r"D:\\")
|
||||
cfg = InstallerConfig(target_drive=detect_target_drive())
|
||||
install_novindesk(cfg)
|
||||
print("[+] NovinDesk installation module completed successfully.")
|
||||
except Exception as e:
|
||||
print(f"[-] Error: {e}")
|
||||
print(f"[-] Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user