124 lines
4.4 KiB
Python
124 lines
4.4 KiB
Python
# TyChat TUI auto installer
|
|
# This is bugged pice of shit because of crossplatform
|
|
# I will only officialy supporting Windows and UNIX-Like systems excluding MacOS and KolibriOS
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
import platform
|
|
import urllib.request
|
|
import zipfile
|
|
|
|
# Configuration, you can change if you like, for example, making a fork of my messenger
|
|
REPO_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client.git"
|
|
PROJECT_DIR = "TyChat-Client-Build"
|
|
VENV_DIR = os.path.join(PROJECT_DIR, "setup-venv")
|
|
ENTRY_POINT = "TUI.py"
|
|
DEPENDENCIES = [
|
|
"pyinstaller",
|
|
"python-socketio",
|
|
"websocket-client",
|
|
"numpy",
|
|
"sounddevice",
|
|
"prompt_toolkit"
|
|
]
|
|
|
|
GREEN = '\033[92m'
|
|
RESET = '\033[0m'
|
|
|
|
def run_command(command, cwd=None, shell=False):
|
|
"""Wrapper to run shell commands."""
|
|
try:
|
|
subprocess.run(command, cwd=cwd, check=True, shell=shell)
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"[ERROR] Command failed: {' '.join(command)}")
|
|
sys.exit(1)
|
|
|
|
def get_venv_paths():
|
|
"""Determine paths based on the operating system and check for valid executables."""
|
|
# Resolve to an absolute path so altering cwd downstream doesn't break relative lookups
|
|
absolute_venv = os.path.abspath(VENV_DIR)
|
|
|
|
if platform.system() == "Windows":
|
|
return os.path.join(absolute_venv, "Scripts", "python.exe"), os.path.join(absolute_venv, "Scripts", "pip.exe")
|
|
|
|
# Check for python3, fallback to python
|
|
python_path = os.path.join(absolute_venv, "bin", "python3")
|
|
if not os.path.exists(python_path):
|
|
python_path = os.path.join(absolute_venv, "bin", "python")
|
|
|
|
# Check for pip3, fallback to pip
|
|
pip_path = os.path.join(absolute_venv, "bin", "pip3")
|
|
if not os.path.exists(pip_path):
|
|
pip_path = os.path.join(absolute_venv, "bin", "pip")
|
|
|
|
return python_path, pip_path
|
|
|
|
def download_and_extract_zip(url, target_dir):
|
|
"""Downloads the repository source ZIP and extracts its contents into target_dir."""
|
|
zip_path = "repo_archive.zip"
|
|
try:
|
|
print(" -> Git not found. Downloading source ZIP archive...")
|
|
# Download the zip file
|
|
urllib.request.urlretrieve(url, zip_path)
|
|
|
|
print(" -> Extracting archive...")
|
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
|
# The archive extracts into a root folder like 'TyChat-Client' or 'TyChat-Client-main'
|
|
# We look at the first directory level inside the ZIP
|
|
root_in_zip = zip_ref.namelist()[0].split('/')[0]
|
|
zip_ref.extractall(".")
|
|
|
|
# Rename the extracted folder to match your expected PROJECT_DIR
|
|
if os.path.exists(root_in_zip):
|
|
os.rename(root_in_zip, target_dir)
|
|
|
|
except Exception as e:
|
|
print(f"[ERROR] Failed to download or extract the repository ZIP: {e}")
|
|
sys.exit(1)
|
|
finally:
|
|
# Clean up the downloaded zip file
|
|
if os.path.exists(zip_path):
|
|
os.remove(zip_path)
|
|
|
|
def main():
|
|
# Cleanup existing build
|
|
if os.path.exists(PROJECT_DIR):
|
|
shutil.rmtree(PROJECT_DIR)
|
|
|
|
print("[*] Cloning repository...")
|
|
# Check if git is available in the system PATH
|
|
if shutil.which("git"):
|
|
run_command(["git", "clone", REPO_URL, PROJECT_DIR])
|
|
else:
|
|
# Fallback to the direct zip archive if git is missing
|
|
zip_url = "https://git.idkmail.ru/lohrrrr/TyChat-Client/archive/main.zip"
|
|
download_and_extract_zip(zip_url, PROJECT_DIR)
|
|
|
|
print("[*] Creating virtual environment...")
|
|
run_command([sys.executable, "-m", "venv", VENV_DIR])
|
|
|
|
python_exe, pip_exe = get_venv_paths()
|
|
|
|
print("[*] Upgrading pip...")
|
|
run_command([python_exe, "-m", "pip", "install", "--upgrade", "pip"])
|
|
|
|
print("[*] Installing dependencies...")
|
|
for dep in DEPENDENCIES:
|
|
print(f" -> Installing {dep}...")
|
|
run_command([pip_exe, "install", dep])
|
|
|
|
print("[*] Building standalone binary...")
|
|
# Run PyInstaller (and pray to the god)
|
|
run_command([python_exe, "-m", "PyInstaller", "--onefile", "--name", "TyChat", ENTRY_POINT], cwd=PROJECT_DIR)
|
|
|
|
dist_dir = os.path.join(PROJECT_DIR, "dist")
|
|
|
|
if os.path.exists(dist_dir):
|
|
print(f"\n{GREEN}Your executable file is located in {os.path.abspath(dist_dir)}{RESET}")
|
|
else:
|
|
print(f"\n[!] Build complete, but 'dist' directory not found at: {dist_dir}.")
|
|
|
|
if __name__ == "__main__":
|
|
main() |