Skip to content
This repository was archived by the owner on Mar 7, 2025. It is now read-only.

Commit b3e09eb

Browse files
author
Raven
committed
Many various improvements
1 parent 1091d2f commit b3e09eb

File tree

1 file changed

+82
-99
lines changed

1 file changed

+82
-99
lines changed

toolbox.py

Lines changed: 82 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,39 @@
44
import urllib.request
55
import hashlib
66
from pathlib import Path
7-
import subprocess
8-
from tqdm import tqdm
97
import shutil
108
import zipfile
119
from datetime import datetime
10+
import warnings
11+
import platform
12+
from tqdm import tqdm
13+
from tqdm.std import TqdmWarning
14+
from colorama import Fore, Style
15+
import argparse
16+
17+
warnings.filterwarnings("ignore", category=TqdmWarning)
1218

1319
def get_package_file_path():
14-
if sys.platform == "win32":
20+
if platform.system() == "Windows":
1521
return Path(os.getenv('APPDATA')) / "ravendevteam" / "toolbox" / "packages.json"
1622
else:
1723
return Path.home() / "Library" / "Application Support" / "ravendevteam" / "toolbox" / "packages.json"
1824

1925
def get_installation_path(package_name):
20-
if sys.platform == "win32":
26+
if platform.system() == "Windows":
2127
return Path(os.getenv('APPDATA')) / "ravendevteam" / package_name
2228
else:
2329
return Path.home() / "Library" / "Application Support" / "ravendevteam" / package_name
2430

2531
def handle_error(message):
26-
print(f"Error: {message}")
32+
print(Fore.RED + f"Error: {message}" + Style.RESET_ALL)
2733
sys.exit(1)
2834

35+
def handle_warning(message):
36+
print(Fore.YELLOW + f"Warning: {message}" + Style.RESET_ALL)
37+
2938
def get_record_file_path():
30-
if sys.platform == "win32":
39+
if platform.system() == "Windows":
3140
return Path(os.getenv('APPDATA')) / "ravendevteam" / "record.json"
3241
else:
3342
return Path.home() / "Library" / "Application Support" / "ravendevteam" / "record.json"
@@ -48,17 +57,18 @@ def write_record(record):
4857
with open(record_file, 'w') as f:
4958
json.dump(record, f, indent=4)
5059

51-
def uninstall_package(package_name):
60+
def uninstall_package(package_name, skip_confirmation):
5261
try:
5362
install_path = get_installation_path(package_name)
5463
if not install_path.exists():
5564
handle_error(f"Package '{package_name}' is not installed.")
56-
confirmation = input(f"Are you sure you want to uninstall '{package_name}'? (Y/N): ").strip().lower()
57-
if confirmation != 'y':
58-
print(f"Uninstallation of '{package_name}' cancelled.")
59-
return
65+
if not skip_confirmation:
66+
confirmation = input(f"Are you sure you want to uninstall '{package_name}'? (Y/N): ").strip().lower()
67+
if confirmation != 'y':
68+
print(Fore.WHITE + f"Uninstallation of '{package_name}' cancelled." + Style.RESET_ALL)
69+
return
6070
shutil.rmtree(install_path)
61-
print(f"'{package_name}' has been successfully uninstalled.")
71+
print(Fore.GREEN + f"'{package_name}' has been successfully uninstalled." + Style.RESET_ALL)
6272
record = read_record()
6373
if package_name in record:
6474
del record[package_name]
@@ -71,21 +81,14 @@ def update_packages():
7181
try:
7282
with open(get_package_file_path(), 'r') as f:
7383
data = json.load(f)
74-
update_url = data.get('updateurl', None)
84+
update_url = data.get('updateurl', default_update_url)
7585
except (FileNotFoundError, json.JSONDecodeError):
76-
update_url = None
77-
if not update_url:
7886
update_url = default_update_url
79-
print(f"Warning: No update URL found or the package list is missing. Using default update URL: {default_update_url}")
80-
print("Please note that the above error is normal upon first time updating.")
81-
print("Updating package list from server...")
87+
print(Fore.WHITE + f"Using default update URL: {default_update_url}" + Style.RESET_ALL)
88+
print(Fore.WHITE + "Updating package list from server..." + Style.RESET_ALL)
8289
try:
8390
urllib.request.urlretrieve(update_url, get_package_file_path())
84-
print("Update successful!")
85-
except urllib.error.HTTPError as e:
86-
handle_error(f"HTTP Error: {e.code} - {e.reason}. Please check the update URL or try again later.")
87-
except urllib.error.URLError as e:
88-
handle_error(f"URL Error: {str(e)}. Please check your internet connection or try again later.")
91+
print(Fore.GREEN + "Update successful!" + Style.RESET_ALL)
8992
except Exception as e:
9093
handle_error(f"Failed to update packages: {str(e)}. Please try again or check your settings.")
9194

@@ -115,115 +118,95 @@ def validate_checksum(file_path, expected_hash):
115118
return sha256_hash.hexdigest() == expected_hash
116119

117120
def create_shortcut(target, shortcut_name):
118-
if sys.platform == "win32":
119-
from win32com.client import Dispatch
120-
shell = Dispatch('WScript.Shell')
121-
desktop = shell.SpecialFolders('Desktop')
122-
shortcut = shell.CreateShortCut(os.path.join(desktop, f"{shortcut_name}.lnk"))
123-
shortcut.TargetPath = target
124-
shortcut.WorkingDirectory = os.path.dirname(target)
125-
shortcut.IconLocation = target
126-
shortcut.save()
127-
else:
128-
os.symlink(target, Path.home() / "Desktop" / f"{shortcut_name}.app")
121+
try:
122+
if platform.system() == "Windows":
123+
from win32com.client import Dispatch
124+
shell = Dispatch('WScript.Shell')
125+
desktop = shell.SpecialFolders('Desktop')
126+
shortcut = shell.CreateShortCut(os.path.join(desktop, f"{shortcut_name}.lnk"))
127+
shortcut.TargetPath = target
128+
shortcut.WorkingDirectory = os.path.dirname(target)
129+
shortcut.IconLocation = target
130+
shortcut.save()
131+
else:
132+
os.symlink(target, Path.home() / "Desktop" / f"{shortcut_name}.app")
133+
except Exception:
134+
handle_warning(f"Could not create a shortcut for '{shortcut_name}'. This will not affect the installation.")
129135

130-
def install_package(package_name):
136+
def install_package(package_name, skip_confirmation):
131137
try:
132138
with open(get_package_file_path(), 'r') as f:
133139
data = json.load(f)
134-
package = next((pkg for pkg in data.get("packages", []) if pkg["name"].lower() == package_name.lower()), None)
140+
packages = data.get("packages", [])
141+
if package_name == '*':
142+
for package in packages:
143+
install_package(package['name'], skip_confirmation)
144+
return
145+
package = next((pkg for pkg in packages if pkg["name"].lower() == package_name.lower()), None)
135146
if not package:
136147
handle_error(f"Package '{package_name}' not found in the package list.")
137-
platform = "Windows" if sys.platform == "win32" else "macOS"
138-
if platform not in package["os"]:
139-
handle_error(f"'{package_name}' is not available for your platform ({platform}).")
140-
url = package["url"][platform]
141-
sha256 = package["sha256"][platform]
142-
print(f"Installing {package_name} (v{package['version']}) for {platform}...")
148+
platform_name = platform.system()
149+
if platform_name not in package["os"]:
150+
handle_error(f"'{package_name}' is not available for your platform ({platform_name}).")
151+
url = package["url"][platform_name]
152+
sha256 = package["sha256"][platform_name]
153+
if not skip_confirmation:
154+
confirmation = input(f"Are you sure you want to install '{package_name}'? (Y/N): ").strip().lower()
155+
if confirmation != 'y':
156+
print(Fore.WHITE + f"Installation of '{package_name}' cancelled." + Style.RESET_ALL)
157+
return
158+
print(Fore.WHITE + f"Installing {package_name} (v{package['version']}) for {platform_name}..." + Style.RESET_ALL)
143159
install_path = get_installation_path(package_name)
144160
install_path.mkdir(parents=True, exist_ok=True)
145161
download_path = install_path / f"{package_name}.{url.split('.')[-1]}"
146162
with tqdm(total=100, desc="Downloading", unit='%', bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}') as pbar:
147163
urllib.request.urlretrieve(url, download_path, reporthook=lambda count, block_size, total_size: pbar.update(block_size / total_size * 100))
148-
print(f"Downloaded {package_name} to {download_path}")
164+
print(Fore.WHITE + f"Downloaded {package_name} to {download_path}" + Style.RESET_ALL)
149165
if not validate_checksum(download_path, sha256):
150166
handle_error(f"Checksum mismatch for {package_name}. Installation aborted.")
151-
if sys.platform == "darwin" and download_path.suffix == '.zip':
152-
print("Extracting the package...")
153-
with zipfile.ZipFile(download_path, 'r') as zip_ref:
154-
zip_ref.extractall(install_path)
155-
print(f"Extracted {package_name} to {install_path}")
156-
download_path.unlink()
157-
print(f"Removed the ZIP file {download_path}")
158167
if install_path.exists():
159-
print(f"{package_name} installed successfully!")
160-
168+
print(Fore.GREEN + f"{package_name} installed successfully!" + Style.RESET_ALL)
161169
if package['shortcut']:
162170
target = next(install_path.glob('*'), None)
163171
if target:
164172
create_shortcut(str(target), package_name)
165-
print(f"A shortcut for {package_name} has been created on your desktop.")
166-
else:
167-
print(f"Warning: Couldn't find the main executable for {package_name} to create a shortcut.")
168173
record = read_record()
169174
record[package_name] = {
170175
"version": package["version"],
171176
"installed_on": datetime.now().isoformat()
172177
}
173178
write_record(record)
174-
else:
175-
handle_error(f"Installation path does not exist after extraction. Installation failed.")
176179
except FileNotFoundError:
177180
handle_error("Package list not found. Try updating the package list using 'update'.")
178181
except Exception as e:
179182
handle_error(f"An error occurred during installation: {str(e)}.")
180183

181-
def display_help():
182-
print("Toolbox Package Manager")
183-
print("Version: 2.1.0")
184-
print("Usage: toolbox.py <command> <package>")
185-
print("Possible commands:")
186-
print(" list - List available packages")
187-
print(" install - Install a specified package")
188-
print(" uninstall - Uninstall a specified package")
189-
print(" update - Update the package list from the server")
190-
print(" json - Print the path to the packages.json file")
191-
print("License: https://ravendevteam.org/files/BSD-3-Clause.txt")
192-
193-
def print_json_path():
194-
print(f"{get_package_file_path()}")
195-
196184
def main():
197-
package_file_path = get_package_file_path()
198-
if not package_file_path.exists():
199-
print("Package list not found.")
200-
print("It looks like you need to update the package list.")
201-
print("Attempting to download the latest packages.json...")
202-
update_packages()
203-
if not package_file_path.exists():
204-
handle_error("Failed to download the package list.")
205-
if len(sys.argv) < 2:
206-
display_help()
207-
sys.exit(0)
208-
command = sys.argv[1].lower()
209-
if command == "list":
185+
parser = argparse.ArgumentParser(description="Toolbox Package Manager")
186+
parser.add_argument("command", choices=["list", "install", "uninstall", "update", "help", "json"], help="Command to execute", nargs="?")
187+
parser.add_argument("package", nargs="?", help="Package name (required for install and uninstall)")
188+
parser.add_argument("-y", "--yes", action="store_true", help="Skip confirmation prompts")
189+
args = parser.parse_args()
190+
if not args.command:
191+
parser.print_help()
192+
return
193+
if args.command == "list":
210194
list_packages()
211-
elif command == "install":
212-
if len(sys.argv) < 3:
195+
elif args.command == "install":
196+
if not args.package:
213197
handle_error("You must specify the package name to install.")
214-
install_package(sys.argv[2])
215-
elif command == "uninstall":
216-
if len(sys.argv) < 3:
198+
install_package(args.package, args.yes)
199+
elif args.command == "uninstall":
200+
if not args.package:
217201
handle_error("You must specify the package name to uninstall.")
218-
uninstall_package(sys.argv[2])
219-
elif command == "update":
202+
uninstall_package(args.package, args.yes)
203+
elif args.command == "update":
220204
update_packages()
221-
elif command == "help":
222-
display_help()
223-
elif command == "json":
224-
print_json_path()
225-
else:
226-
handle_error(f"Unknown command: {command}.")
205+
elif args.command == "help":
206+
parser.print_help()
207+
elif args.command == "json":
208+
print(get_package_file_path())
209+
227210

228211
if __name__ == "__main__":
229-
main()
212+
main()

0 commit comments

Comments
 (0)