-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatch_nova.py
More file actions
213 lines (180 loc) · 10.9 KB
/
patch_nova.py
File metadata and controls
213 lines (180 loc) · 10.9 KB
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
from patch_modules.log_viewer import show_log
from patch_modules.check_software import check_software, is_admin
from patch_modules.custom_dialog import custom_dialog, get_user_consent
from patch_modules.set_bg_image import set_background_with_label
from patch_modules.get_proc_info_windows import plot_win_cpu_usage_from_csv
from patch_modules.get_proc_info_linux import plot_linux_cpu_usage_from_csv
from patch_modules.get_proc_info_mac import plot_mac_cpu_usage_from_csv
import tkinter as tk
from tkinter import ttk, messagebox, font
import platform
import subprocess
import distro
import logging
from logging.handlers import RotatingFileHandler
import ctypes
import sys
import os
class UpdateCheckerApp:
def __init__(self, root):
self.root = root
self.root.title("Update Checker")
# INCREASE THE INITIAL SIZE OF THE MAIN WINDOW
self.root.geometry('1000x500')
self.root.configure(bg='#fb8200')
# ENHANCED FONT AND COLOR CONFIGURATION FOR LARGER UI ELEMENTS
self.font_style = ("Consolas", 16)
self.button_color = "#15065c"
self.text_color = "#FFFFFF"
self.button_text_color = "#FFFFFF"
self.label_bg_color = "#2c99b4"
# HARDWARE INFO LABEL
self.hardware_info_label = tk.Label(root, text="", bg=self.label_bg_color, fg=self.text_color, font=self.font_style)
self.hardware_info_label.pack(pady=20) # INCREASE VERTICAL PADDING
# DISPLAY HARDWARE INFORMATION
self.hardware_info_label = tk.Label(root, text="")
self.hardware_info_label.pack()
self.get_hardware_info()
# LOADING INDICATOR
self.loading_indicator = ttk.Progressbar(root, orient="horizontal", mode="indeterminate")
# STATUS LABEL
self.status_label = tk.Label(root, text="", bg=self.label_bg_color, fg=self.text_color, font=self.font_style)
# LARGER BUTTONS WITH INCREASED PADDING
self.check_updates_button = tk.Button(root, text="Install System Updates", command=self.check_updates, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.check_updates_button.pack(pady=10) # INCREASE VERTICAL PADDING
self.check_software_updates_button = tk.Button(root, text="Check Installed Software", command=self.check_software_updates, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.check_software_updates_button.pack(pady=10) # INCREASE VERTICAL PADDING
self.logger = logging.getLogger("UpdateCheckerApp")
self.show_logs_button = tk.Button(root, text="Show Logs", command=self.show_logs, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
# self.show_logs_button = tk.Button(root, text="Show Logs", command=lambda: show_logs(self, self.root), bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.show_logs_button.pack(pady=10)
# SHOW TOP 10 PROCESSES FOR WINDOWS
if platform.system() == 'Windows':
self.show_win_proc_button = tk.Button(root, text=f"%CPU Usage(10 Secs)", command=self.get_windows_processes, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.show_win_proc_button.pack(pady=10)
# SHOW TOP 10 PROCESSES FOR LINUX
if platform.system() == 'Linux':
self.show_linux_proc_button = tk.Button(root, text="%CPU Usage (10 Secs)", command=self.get_linux_processes, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.show_linux_proc_button.pack(pady=10)
if platform.system() == 'Darwin':
# SHOW TOP 10 PROCESSES FOR LINUX
self.show_mac_proc_button = tk.Button(root, text="%CPU Usage (10 Secs)", command=self.get_mac_processes, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.show_mac_proc_button.pack(pady=10)
# SHOW ABOUT BUTTON
self.show_about_patchnova = tk.Button(root, text="About PatchNova", command=self.show_about, bg=self.button_color, fg=self.button_text_color, font=self.font_style)
self.show_about_patchnova.pack(pady=10)
# SETUP LOGGING
self.setup_logging()
def get_windows_processes(self):
return plot_win_cpu_usage_from_csv()
def get_linux_processes(self):
return plot_linux_cpu_usage_from_csv()
def get_mac_processes(self):
return plot_mac_cpu_usage_from_csv()
def get_user_consent(self):
return messagebox.askyesno("User Consent", "Do you want to proceed?")
def show_logs(self):
return show_log(self, self.root)
def check_software_updates(self):
return check_software(self, self.root)
def create_custom_dialog(self, title, message, width, height):
return custom_dialog(self, title, message, width, height)
def show_about(self):
title = "About PatchNova"
text = f"PatchNova is a streamlined, local update management application designed for efficient software and system updates.\n\nThis desktop tool offers a user-friendly interface to monitor and manage updates for your operating system, ensuring optimal performance, security, and efficiency.\n\nWith features like automated update checks, verbose log files, and user consent control, PatchNova empowers users to stay ahead of the curve in maintaining a secure and up-to-date computing environment."
return self.create_custom_dialog(title, text, 500,400)
def setup_logging(self):
# CREATE A LOGGER
self.logger.setLevel(logging.DEBUG)
# CREATE A FORMATTER AND ADD IT TO THE HANDLER
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
# CREATE A ROTATING FILE HANDLER FOR UPDATE HISTORY
self.history_handler = RotatingFileHandler("update_history.log", maxBytes=1024 * 1024, backupCount=5)
self.history_handler.setLevel(logging.INFO)
self.history_handler.setFormatter(formatter)
self.logger.addHandler(self.history_handler)
# CREATE A ROTATING FILE HANDLER FOR ERRORS
self.error_handler = RotatingFileHandler("error_log.log", maxBytes=1024 * 1024, backupCount=5)
self.error_handler.setLevel(logging.ERROR)
self.error_handler.setFormatter(formatter)
self.logger.addHandler(self.error_handler)
def get_hardware_info(self):
system_info = platform.uname()
info_text = f"System: {system_info.system}\nNode Name: {system_info.node}\n" \
f"Release: {system_info.release}\nVersion: {system_info.version}\n" \
f"Machine: {system_info.machine}\nProcessor: {system_info.processor}"
self.hardware_info_label.config(text=info_text)
def show_loading_indicator(self):
self.loading_indicator.pack(pady=10)
self.loading_indicator.start()
def hide_loading_indicator(self):
self.loading_indicator.stop()
self.loading_indicator.pack_forget()
def update_status_label(self, text):
self.status_label.config(text=text)
self.status_label.pack(pady=10)
def check_updates(self):
# self.get_hardware_info()
get_update_consent = get_user_consent("Do you want to install your system updates?")
if get_update_consent:
doublecheck_update_consent = get_user_consent("Are you sure?")
# DOUBLE-CHECK USER CONSENT
if doublecheck_update_consent:
# CHECK IF PLATFORM IS WINDOWS
if platform.system() == 'Windows':
# TRIGGER WINDOWS UPDATES
subprocess.run(["powershell", "Install-Module PSWindowsUpdate -Force -AllowClobber -Scope CurrentUser"])
# CHECK IF ADMIN OR ELEVATE PRIVS
if is_admin():
self.logger.info("Windows update is running as admin user")
command = "Get-WindowsUpdate -Install -AcceptAll"
os.system(f'powershell -Command "{command}"')
else:
# RE-RUN THE SCRIPT WITH ADMIN RIGHTS
self.logger.info("Windows update is elevating privileges as admin user")
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
self.logger.info("Windows update is running as admin user")
self.logger.info("Windows Update completed")
# CHECK IF PLATFORM IS MAC
elif platform.system() == 'Darwin':
# TRIGGER MACOS UPDATE
subprocess.run(["softwareupdate", "-i", "-a"])
self.logger.info("macOS Update completed")
# CHECK IF PLATFORM IS LINUX
elif platform.system() == 'Linux':
# USE DISTRO.ID() TO GET THE DISTRIBUTION ID AS A STRING
dist_id = distro.id()
update_command = ""
if "ubuntu" in dist_id or "debian" in dist_id:
subprocess.run(["sudo", "apt-get", "update"])
update_command = "sudo apt-get upgrade -y"
elif "fedora" in dist_id or "centos" in dist_id:
update_command = "sudo dnf update"
else:
self.create_custom_dialog("Linux Update Information",
"Your Linux distribution is not supported for automatic updates through this script.",
500,200)
self.logger.error("The Linux distribution is not supported for automatic updates through this script")
return
self.create_custom_dialog("Update Information", "System update complete.",
500,100)
self.logger.info(f"Linux update completed for: {dist_id}")
# RUN THE UPDATE COMMAND IN THE TERMINAL
subprocess.run(update_command.split())
else:
self.create_custom_dialog("Unsupported System",
"Updates are not supported for the current operating system.",
500,200)
self.logger.error("Updates are not supported for the current operating system")
self.logger.info("Update process completed.")
else:
self.create_custom_dialog("User Does Not Consent",
"Understood. PatchNova will not install any updates on your system.",
500,200)
self.logger.info("User cancelled update installation process")
if __name__ == "__main__":
image_path = "assets/PatchNovaLogo2.png"
root = tk.Tk()
set_background_with_label(root, image_path)
app = UpdateCheckerApp(root)
root.mainloop()