-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstall.py
193 lines (165 loc) · 7.83 KB
/
install.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import os
import platform
import shutil
import subprocess
import sys
import tkinter as tk
from tkinter import messagebox
import logging
VENV_DIR = ".venv"
MAX_RETRIES = 3
# Assign complexity scores to dependencies
DEPENDENCIES = {
"python3": 1,
"pip3": 1,
"pygame": 2,
"pyinstaller": 3,
}
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def print_status(message, emoji="ℹ️"):
"""Print status messages with an emoji."""
logger.info(f"{emoji} {message}")
def check_command(command):
"""Check if a command exists on the system."""
return shutil.which(command) is not None
def execute_with_retries(command, description, retries=MAX_RETRIES, alternative_method=None):
"""Execute a command with retry logic and an alternative method if available."""
for attempt in range(retries):
try:
subprocess.check_call(command, shell=True)
print_status(f"{description} completed successfully.", "✅")
return True
except subprocess.CalledProcessError:
print_status(f"❌ {description} failed. Attempt {attempt + 1}/{retries}.", "❌")
if attempt == retries - 1 and alternative_method:
print_status("Attempting alternative method...", "⚠️")
alternative_method()
if not alternative_method:
break
sys.exit(1)
def ensure_dependency_installed(dependency, install_command, description, alternative_method=None):
"""Ensure a dependency is installed based on its complexity."""
if not check_command(dependency):
print_status(f"{description} not found. Installing...", "🔍")
execute_with_retries(install_command, f"{description} installation", alternative_method=alternative_method)
else:
print_status(f"{description} already installed.", "✅")
def create_virtual_env():
"""Create and activate a virtual environment if it doesn't exist."""
if not os.path.exists(VENV_DIR):
print_status("Creating virtual environment...", "🔧")
subprocess.check_call([sys.executable, "-m", "venv", VENV_DIR])
activate_script = os.path.join(VENV_DIR, "bin", "activate")
if platform.system() == "Windows":
activate_script += ".bat"
print_status(f"Activating virtual environment: {activate_script}", "🔧")
exec(open(activate_script).read(), dict(__file__=activate_script))
def ensure_python_and_pip():
"""Ensure Python3 and pip3 are installed depending on the operating system."""
system = platform.system()
if system == "Darwin": # macOS
ensure_dependency_installed("python3", "brew install python3", "Python3")
ensure_dependency_installed("pip3", "python3 -m ensurepip --upgrade", "pip3")
elif system == "Linux":
ensure_dependency_installed("python3", "sudo apt install -y python3", "Python3")
ensure_dependency_installed("pip3", "sudo apt install -y python3-pip", "pip3")
def install_pygame():
"""Ensure Pygame is installed."""
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "pygame"])
print_status("Pygame installed successfully.", "✅")
except subprocess.CalledProcessError as e:
print_status("Attempting to bypass 'externally-managed-environment' error...", "⚠️")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "--break-system-packages", "pygame"])
print_status("Pygame installed successfully with --break-system-packages.", "✅")
except subprocess.CalledProcessError as e:
logger.error(f"Failed to install Pygame even with --break-system-packages: {str(e)}")
logger.info("💡 Tip: Visit https://www.pygame.org/wiki/GettingStarted for help.")
sys.exit(1)
def install_pyinstaller():
"""Ensure PyInstaller is installed."""
try:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "pyinstaller"]
)
print_status("PyInstaller installed successfully.", "✅")
except subprocess.CalledProcessError as e:
print_status("Attempting to bypass 'externally-managed-environment' error...", "⚠️")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "--break-system-packages", "pyinstaller"])
print_status("PyInstaller installed successfully with --break-system-packages.", "✅")
except subprocess.CalledProcessError as e:
logger.error(f"Failed to install PyInstaller even with --break-system-packages: {str(e)}")
logger.info("💡 Tip: Visit https://www.pyinstaller.org/ for help.")
sys.exit(1)
def install_dependencies_in_order():
"""Install all dependencies based on their complexity score."""
sorted_dependencies = sorted(DEPENDENCIES.items(), key=lambda item: item[1])
for dep, __complexity in sorted_dependencies:
if dep == "python3":
ensure_python_and_pip()
elif dep == "pip3":
ensure_python_and_pip() # pip3 is handled with Python
elif dep == "pygame":
install_pygame()
elif dep == "pyinstaller":
install_pyinstaller()
def create_executable():
"""Create the executable using PyInstaller."""
system = platform.system()
try:
subprocess.check_call(
["pyinstaller", "--onefile", "--windowed", "ubuntu_boost.py"]
)
dist_path = os.path.join("dist", "ubuntu_boost")
if system == "Windows":
print_status("Executable created for Windows (ubuntu_boost.exe) in the 'dist/' folder.", "✅")
elif system == "Darwin":
print_status("Executable created for macOS (ubuntu_boost.app) in the 'dist/' folder.", "✅")
elif system == "Linux":
print_status("Executable created for Linux (ubuntu_boost) in the 'dist/' folder.", "✅")
os.chmod(dist_path, 0o755)
print_status(f"Set executable permissions for {dist_path}.", "🔧")
except subprocess.CalledProcessError as e:
logger.error(f"Failed to create the executable: {str(e)}")
messagebox.showerror("Executable Creation Failed", f"Failed to create the executable: {str(e)}")
sys.exit(1)
def is_display_available():
"""Check if the DISPLAY environment variable is set, indicating a GUI is available."""
return os.getenv("DISPLAY") is not None
def main():
try:
create_virtual_env()
print_status("Checking and installing dependencies...", "🔍")
install_dependencies_in_order()
print_status("Creating the executable...", "🚀")
create_executable()
print_status("Done.", "🎉")
except Exception as e:
logger.error(f"An error occurred: {str(e)}")
logger.info("💡 Tip: Check https://support.com/installation for troubleshooting help.")
sys.exit(1)
def main_no_gui():
"""Main function to run when no display is available."""
print_status("Oh no GUI unavailable! Running in non-GUI mode.", "🔧")
main()
# GUI Functionality to Add Install Button
def create_install_button():
if is_display_available():
root = tk.Tk()
root.title("UbuntuBoost Installer")
tk.Label(root, text="UbuntuBoost Installer", font=("Helvetica", 16)).pack(pady=10)
tk.Label(root, text="Press 'Install' to start the installation process.", font=("Helvetica", 12)).pack(pady=5)
install_button = tk.Button(root, text="Install", command=main, width=20)
install_button.pack(pady=10)
exit_button = tk.Button(root, text="Exit", command=root.quit, width=20)
exit_button.pack(pady=10)
root.mainloop()
else:
print_status("No display available, skipping GUI.", "⚠️")
main_no_gui()
if __name__ == "__main__":
create_install_button()