Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions src/toolManager/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,21 @@
except ImportError:
pass # Will handle gracefully later if missing

from registry import TOOLS, CATEGORIES
from paths import get_toolmanager_root, get_install_state_path
from constants import IS_WINDOWS
from config import ConfigManager

# ==================== CONFIG ====================
BASE_DIR = Path(__file__).resolve().parent
INFO_JSON = BASE_DIR / "information.json"
BASE_DIR = get_toolmanager_root()
INFO_JSON = get_install_state_path()
FULL_GUI = BASE_DIR / "gui_fixed.py"
PYTHON = sys.executable

ANALOG_TOOLS = ["esim", "kicad", "ngspice"]
DIGITAL_TOOLS = ["esim", "kicad", "ngspice", "ghdl", "verilator", "llvm"]
ANALOG_TOOLS = CATEGORIES["analog"]
DIGITAL_TOOLS = CATEGORIES["digital"]

TOOL_LABELS = {
"esim": "eSim",
"kicad": "KiCad",
"ngspice": "Ngspice",
"ghdl": "GHDL",
"verilator": "Verilator",
"llvm": "LLVM",
}
TOOL_LABELS = {tid: TOOLS[tid].label for tid in DIGITAL_TOOLS}

TOOL_VERSIONS = {
"esim": "2.4",
Expand Down Expand Up @@ -68,14 +66,11 @@ def relaunch_as_admin():
def load_installed_versions():
versions = {k: "Not installed" for k in TOOL_LABELS}
try:
if INFO_JSON.exists():
with open(INFO_JSON) as f:
data = json.load(f)
for pkg in data.get("important_packages", []):
name = pkg.get("package_name", "")
ver = pkg.get("version", "Not installed")
if name in versions and ver not in ("", "Not installed"):
versions[name] = ver
config = ConfigManager()
for tool_id in TOOL_LABELS:
state = config.get_tool_state(tool_id)
if state and state.get("version", "") not in ("", "Not installed"):
versions[tool_id] = state["version"]
except Exception as e:
print(f"Could not load version info: {e}")
return versions
Expand Down Expand Up @@ -656,7 +651,7 @@ def _run_uninstall(self, tools, label):
subprocess.Popen(
[PYTHON, backend, "uninstall", tool, "none"],
creationflags=(subprocess.CREATE_NO_WINDOW
if sys.platform == "win32" else 0)
if IS_WINDOWS else 0)
)
QMessageBox.information(
self, "Uninstall Started",
Expand All @@ -669,7 +664,7 @@ def _run_uninstall(self, tools, label):


def main():
if sys.platform == "win32" and not is_admin():
if IS_WINDOWS and not is_admin():
# Note: We deliberately skip a manual PyQt consent dialog here because
# Windows will natively prompt the user with a UAC shield anyway.
relaunch_as_admin()
Expand Down
60 changes: 13 additions & 47 deletions src/toolManager/tool_manager_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,21 @@
from utils import (
run_cmd_safe, run_cmd_stream, which, print_status,
DEFAULT_MSYS2_PATH, DEFAULT_ESIM_DIR, WIN_KICAD_PATHS,
WIN_NGSPICE_PATHS, WIN_LLVM_PATHS, get_msys2_bash,
WIN_NGSPICE_PATHS, WIN_LLVM_PATHS, get_msys2_bash,
get_msys2_mingw_bin, get_msys2_mingw_root
)
from constants import IS_WINDOWS
from paths import get_toolmanager_root, get_install_state_path, get_download_cache_dir
from config import ConfigManager

if sys.platform == "win32":
if IS_WINDOWS:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='ignore')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='ignore')

BASE_DIR = Path(__file__).resolve().parent
STATE_FILE = BASE_DIR / "information.json"
BASE_DIR.mkdir(parents=True, exist_ok=True)

BASE_DIR = get_toolmanager_root()
STATE_FILE = get_install_state_path()
MSYS2_PATH = DEFAULT_MSYS2_PATH

DOWNLOAD_DIR = BASE_DIR / "Download"
DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
DOWNLOAD_DIR = get_download_cache_dir()

VERILATOR_VERSIONS = {
"5.006": "verilator-5.006.7z",
Expand Down Expand Up @@ -202,7 +201,7 @@ def _find_ngspice_exe():
return which("ngspice") or which("ngspice.exe")

def find_llvm_fixed(version=None):
if platform.system() == "Windows":
if IS_WINDOWS:
import ctypes
HWND_BROADCAST = 0xFFFF
WM_SETTINGCHANGE = 0x001A
Expand Down Expand Up @@ -1137,41 +1136,7 @@ def install_verilator(v, upgrade=False):
except Exception as e:
print_status("install_failed", str(e)[:50], v)

def read_state():
if STATE_FILE.exists():
try:
with open(STATE_FILE) as f:
return json.load(f)
except Exception:
pass
return {"important_packages": []}

def write_state(data):
with open(STATE_FILE, "w") as f:
json.dump(data, f, indent=4)

def update_state(package_name, version):
from datetime import datetime
data = read_state()
for pkg in data["important_packages"]:
if pkg["package_name"] == package_name:
pkg["version"] = version
pkg["installed_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
write_state(data)
return
data["important_packages"].append({
"package_name": package_name,
"version": version,
"installed_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
})
write_state(data)

def get_state_version(package_name):
data = read_state()
for pkg in data["important_packages"]:
if pkg["package_name"] == package_name:
return pkg.get("version")
return None
_config = ConfigManager()


ESIM_DIR = DEFAULT_ESIM_DIR
Expand All @@ -1187,7 +1152,8 @@ def check_esim(target_version):
]
for p in indicators:
if p.exists():
ver = get_state_version("esim") or "unknown"
esim_state = _config.get_tool_state("esim")
ver = esim_state.get("version", "unknown") if esim_state else "unknown"
tv = target_version if target_version != "none" else "latest"
if tv in ("latest", "none") or tv == ver:
print_status("installed", ver, tv)
Expand Down Expand Up @@ -1226,7 +1192,7 @@ def install_esim(target_version, upgrade=False):
time.sleep(20)
for p in [BASE_DIR / "eSim.bat", BASE_DIR / "src" / "frontEnd" / "Application.py", ESIM_DIR / "eSim.bat", ESIM_DIR / "uninst-eSim.exe"]:
if p.exists():
update_state("esim", display_ver)
_config.update_tool_state("esim", display_ver)
print(f"[OK] eSim {display_ver} installed")
print_status("installed", display_ver, target_version)
return
Expand Down
33 changes: 8 additions & 25 deletions src/toolManager/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@
import time
from pathlib import Path

# ==================== CONSTANTS & DEFAULTS ====================

# Default Windows installation paths
DEFAULT_MSYS2_PATH = Path(r"C:\msys64")
DEFAULT_ESIM_DIR = Path(r"C:\FOSSEE\eSim")
from constants import DEFAULT_MSYS2_PATH, DEFAULT_ESIM_DIR
from platform_utils import subprocess_flags

WIN_KICAD_PATHS = [
(r"C:\Program Files\KiCad\9.0\bin\kicad.exe", "9"),
Expand Down Expand Up @@ -62,23 +59,16 @@ def run_cmd_safe(cmd, timeout=30, cwd=None, env=None):
Returns the subprocess.CompletedProcess result or None if failed.
"""
try:
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
creationflags = subprocess.CREATE_NO_WINDOW
else:
startupinfo = None
creationflags = 0
flags = subprocess_flags()

result = subprocess.run(
cmd,
capture_output=True,
text=True,
shell=False,
timeout=timeout,
startupinfo=startupinfo,
creationflags=creationflags,
startupinfo=flags.get("startupinfo"),
creationflags=flags.get("creationflags", 0),
encoding='utf-8',
errors='ignore',
cwd=cwd,
Expand All @@ -95,23 +85,16 @@ def run_cmd_stream(cmd, timeout=900, cwd=None, env=None):
Returns a tuple of (returncode, full_output_string).
"""
try:
if platform.system() == "Windows":
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
cf = subprocess.CREATE_NO_WINDOW
else:
si = None
cf = 0
flags = subprocess_flags()

proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
shell=False,
startupinfo=si,
creationflags=cf,
startupinfo=flags.get("startupinfo"),
creationflags=flags.get("creationflags", 0),
encoding='utf-8',
errors='ignore',
cwd=cwd,
Expand Down