You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
11 KiB
329 lines
11 KiB
#!/usr/bin/env python3
|
|
"""
|
|
Virtual Environment Setup Script for MIDI Arpeggiator
|
|
|
|
This script creates and configures a virtual environment for the project.
|
|
"""
|
|
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import platform
|
|
import shutil
|
|
|
|
def run_command(cmd, cwd=None, check=True):
|
|
"""Run a command and return the result"""
|
|
try:
|
|
print(f"Running: {' '.join(cmd)}")
|
|
result = subprocess.run(cmd, cwd=cwd, check=check, capture_output=True, text=True)
|
|
if result.stdout:
|
|
print(result.stdout)
|
|
return result
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error running command: {e}")
|
|
if e.stderr:
|
|
print(f"Error output: {e.stderr}")
|
|
if check:
|
|
raise
|
|
return e
|
|
|
|
def check_python_version():
|
|
"""Check if Python version is compatible"""
|
|
version = sys.version_info
|
|
if version.major < 3 or (version.major == 3 and version.minor < 8):
|
|
print(f"ERROR: Python {version.major}.{version.minor} is not supported")
|
|
print("Please use Python 3.8 or newer")
|
|
return False
|
|
|
|
print(f"OK: Python {version.major}.{version.minor}.{version.micro} is compatible")
|
|
return True
|
|
|
|
def create_virtual_environment():
|
|
"""Create a virtual environment"""
|
|
project_dir = os.path.dirname(os.path.abspath(__file__))
|
|
venv_dir = os.path.join(project_dir, "venv")
|
|
|
|
if os.path.exists(venv_dir):
|
|
print(f"Virtual environment already exists at {venv_dir}")
|
|
response = input("Do you want to recreate it? (y/N): ")
|
|
if response.lower().startswith('y'):
|
|
print("Removing existing virtual environment...")
|
|
shutil.rmtree(venv_dir)
|
|
else:
|
|
print("Using existing virtual environment")
|
|
return venv_dir
|
|
|
|
print("Creating virtual environment...")
|
|
run_command([sys.executable, "-m", "venv", "venv"], cwd=project_dir)
|
|
|
|
print(f"OK: Virtual environment created at {venv_dir}")
|
|
return venv_dir
|
|
|
|
def get_venv_python(venv_dir):
|
|
"""Get the path to the Python executable in the virtual environment"""
|
|
if platform.system() == "Windows":
|
|
return os.path.join(venv_dir, "Scripts", "python.exe")
|
|
else:
|
|
return os.path.join(venv_dir, "bin", "python")
|
|
|
|
def get_venv_pip(venv_dir):
|
|
"""Get the path to pip in the virtual environment"""
|
|
if platform.system() == "Windows":
|
|
return os.path.join(venv_dir, "Scripts", "pip.exe")
|
|
else:
|
|
return os.path.join(venv_dir, "bin", "pip")
|
|
|
|
def install_dependencies(venv_dir):
|
|
"""Install dependencies in the virtual environment"""
|
|
project_dir = os.path.dirname(os.path.abspath(__file__))
|
|
pip_exe = get_venv_pip(venv_dir)
|
|
python_exe = get_venv_python(venv_dir)
|
|
|
|
# Upgrade pip first
|
|
print("Upgrading pip...")
|
|
run_command([python_exe, "-m", "pip", "install", "--upgrade", "pip"])
|
|
|
|
# Choose requirements file based on platform
|
|
if platform.system() == "Windows":
|
|
requirements_file = "requirements-windows.txt"
|
|
print("Using Windows-specific requirements...")
|
|
else:
|
|
requirements_file = "requirements.txt"
|
|
print("Using standard requirements...")
|
|
|
|
requirements_path = os.path.join(project_dir, requirements_file)
|
|
|
|
if not os.path.exists(requirements_path):
|
|
print(f"ERROR: Requirements file not found: {requirements_path}")
|
|
return False
|
|
|
|
# Install core packages first
|
|
core_packages = [
|
|
"PyQt5>=5.15.0",
|
|
"numpy>=1.21.0",
|
|
"pygame>=2.1.0",
|
|
"mido>=1.2.10"
|
|
]
|
|
|
|
print("Installing core packages...")
|
|
for package in core_packages:
|
|
try:
|
|
run_command([pip_exe, "install", package])
|
|
print(f"OK: Installed {package}")
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"ERROR: Failed to install {package}")
|
|
return False
|
|
|
|
# Try to install RTMIDI (may fail on some systems)
|
|
rtmidi_packages = [
|
|
"python-rtmidi>=1.5.0",
|
|
"python-rtmidi",
|
|
"rtmidi-python>=1.1.0"
|
|
]
|
|
|
|
rtmidi_installed = False
|
|
for package in rtmidi_packages:
|
|
try:
|
|
print(f"Trying to install {package}...")
|
|
run_command([pip_exe, "install", package])
|
|
rtmidi_installed = True
|
|
print(f"OK: Successfully installed {package}")
|
|
break
|
|
except subprocess.CalledProcessError:
|
|
print(f"WARNING: Failed to install {package}, trying next option...")
|
|
|
|
if not rtmidi_installed:
|
|
print("\nWARNING: Could not install any RTMIDI package.")
|
|
print("The application will still work in simulator mode.")
|
|
|
|
print("OK: Dependencies installation completed!")
|
|
return True
|
|
|
|
def create_activation_scripts():
|
|
"""Create convenient activation scripts"""
|
|
project_dir = os.path.dirname(os.path.abspath(__file__))
|
|
venv_dir = os.path.join(project_dir, "venv")
|
|
|
|
if platform.system() == "Windows":
|
|
# Windows batch file
|
|
activate_script = os.path.join(project_dir, "activate.bat")
|
|
with open(activate_script, 'w') as f:
|
|
f.write(f'@echo off\n')
|
|
f.write(f'call "{venv_dir}\\Scripts\\activate.bat"\n')
|
|
f.write(f'echo Virtual environment activated!\n')
|
|
f.write(f'echo Run "python run.py" to start the arpeggiator\n')
|
|
|
|
# PowerShell script
|
|
activate_ps_script = os.path.join(project_dir, "activate.ps1")
|
|
with open(activate_ps_script, 'w') as f:
|
|
f.write(f'& "{venv_dir}\\Scripts\\Activate.ps1"\n')
|
|
f.write(f'Write-Host "Virtual environment activated!" -ForegroundColor Green\n')
|
|
f.write(f'Write-Host "Run \'python run.py\' to start the arpeggiator" -ForegroundColor Cyan\n')
|
|
|
|
run_script = os.path.join(project_dir, "run_in_venv.bat")
|
|
with open(run_script, 'w') as f:
|
|
f.write(f'@echo off\n')
|
|
f.write(f'call "{venv_dir}\\Scripts\\activate.bat"\n')
|
|
f.write(f'python run.py\n')
|
|
|
|
print("OK: Created Windows activation scripts:")
|
|
print(f" - {activate_script}")
|
|
print(f" - {activate_ps_script}")
|
|
print(f" - {run_script}")
|
|
|
|
else:
|
|
# Unix shell script
|
|
activate_script = os.path.join(project_dir, "activate.sh")
|
|
with open(activate_script, 'w') as f:
|
|
f.write('#!/bin/bash\n')
|
|
f.write(f'source "{venv_dir}/bin/activate"\n')
|
|
f.write('echo "Virtual environment activated!"\n')
|
|
f.write('echo "Run \'python run.py\' to start the arpeggiator"\n')
|
|
|
|
os.chmod(activate_script, 0o755)
|
|
|
|
run_script = os.path.join(project_dir, "run_in_venv.sh")
|
|
with open(run_script, 'w') as f:
|
|
f.write('#!/bin/bash\n')
|
|
f.write(f'source "{venv_dir}/bin/activate"\n')
|
|
f.write('python run.py\n')
|
|
|
|
os.chmod(run_script, 0o755)
|
|
|
|
print("OK: Created Unix activation scripts:")
|
|
print(f" - {activate_script}")
|
|
print(f" - {run_script}")
|
|
|
|
def create_dev_requirements():
|
|
"""Create development requirements file"""
|
|
project_dir = os.path.dirname(os.path.abspath(__file__))
|
|
dev_requirements_path = os.path.join(project_dir, "requirements-dev.txt")
|
|
|
|
dev_packages = [
|
|
"# Development dependencies",
|
|
"pytest>=7.0.0",
|
|
"pytest-qt>=4.0.0",
|
|
"black>=22.0.0",
|
|
"flake8>=4.0.0",
|
|
"mypy>=0.950",
|
|
"coverage>=6.0.0"
|
|
]
|
|
|
|
with open(dev_requirements_path, 'w') as f:
|
|
f.write('\n'.join(dev_packages))
|
|
|
|
print(f"OK: Created development requirements: {dev_requirements_path}")
|
|
|
|
def verify_installation(venv_dir):
|
|
"""Verify that the installation works"""
|
|
python_exe = get_venv_python(venv_dir)
|
|
|
|
print("\nVerifying installation...")
|
|
|
|
test_imports = [
|
|
("PyQt5", "PyQt5"),
|
|
("numpy", "NumPy"),
|
|
("pygame", "Pygame"),
|
|
("mido", "Mido")
|
|
]
|
|
|
|
all_good = True
|
|
|
|
for module, display_name in test_imports:
|
|
try:
|
|
result = run_command([python_exe, "-c", f"import {module}; print('OK')"], check=False)
|
|
if result.returncode == 0:
|
|
print(f"OK: {display_name}")
|
|
else:
|
|
print(f"ERROR: {display_name}")
|
|
all_good = False
|
|
except:
|
|
print(f"ERROR: {display_name}")
|
|
all_good = False
|
|
|
|
# Test RTMIDI (optional)
|
|
try:
|
|
result = run_command([python_exe, "-c", "import rtmidi; print('OK')"], check=False)
|
|
if result.returncode == 0:
|
|
print("OK: RTMIDI")
|
|
else:
|
|
print("WARNING: RTMIDI (will use simulator mode)")
|
|
except:
|
|
print("WARNING: RTMIDI (will use simulator mode)")
|
|
|
|
return all_good
|
|
|
|
def main():
|
|
"""Main setup function"""
|
|
# Handle Unicode issues on Windows console
|
|
try:
|
|
print("🎹 MIDI Arpeggiator - Virtual Environment Setup")
|
|
except UnicodeEncodeError:
|
|
print("MIDI Arpeggiator - Virtual Environment Setup")
|
|
print("=" * 50)
|
|
|
|
# Check Python version
|
|
if not check_python_version():
|
|
return 1
|
|
|
|
# Create virtual environment
|
|
try:
|
|
venv_dir = create_virtual_environment()
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to create virtual environment: {e}")
|
|
return 1
|
|
|
|
# Install dependencies
|
|
try:
|
|
if not install_dependencies(venv_dir):
|
|
print("ERROR: Failed to install some dependencies")
|
|
return 1
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to install dependencies: {e}")
|
|
return 1
|
|
|
|
# Create activation scripts
|
|
try:
|
|
create_activation_scripts()
|
|
create_dev_requirements()
|
|
except Exception as e:
|
|
print(f"ERROR: Failed to create scripts: {e}")
|
|
return 1
|
|
|
|
# Verify installation
|
|
if not verify_installation(venv_dir):
|
|
print("WARNING: Some packages failed to install properly")
|
|
print("The application may still work in simulator mode")
|
|
|
|
try:
|
|
print("\n🎉 Virtual environment setup completed successfully!")
|
|
except UnicodeEncodeError:
|
|
print("\nVirtual environment setup completed successfully!")
|
|
try:
|
|
print("\n📋 Next steps:")
|
|
except UnicodeEncodeError:
|
|
print("\nNext steps:")
|
|
if platform.system() == "Windows":
|
|
print(" 1. Activate the environment:")
|
|
print(" • Command Prompt: activate.bat")
|
|
print(" • PowerShell: .\\activate.ps1")
|
|
print(" 2. Run the application:")
|
|
print(" • In activated environment: python run.py")
|
|
print(" • Direct run: run_in_venv.bat")
|
|
else:
|
|
print(" 1. Activate the environment: source activate.sh")
|
|
print(" 2. Run the application: python run.py")
|
|
print(" Or directly: ./run_in_venv.sh")
|
|
|
|
try:
|
|
print("\n💡 Tips:")
|
|
except UnicodeEncodeError:
|
|
print("\nTips:")
|
|
print(" • The virtual environment is in the 'venv' folder")
|
|
print(" • Use 'deactivate' to exit the virtual environment")
|
|
print(" • Delete 'venv' folder to completely remove the environment")
|
|
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|