addet checkpkg.py to check packages from different packagemanagers
This commit is contained in:
parent
c8ae3809da
commit
6ca12cb426
2 changed files with 262 additions and 0 deletions
186
checkpkg.py
Executable file
186
checkpkg.py
Executable file
|
@ -0,0 +1,186 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import urllib.request
|
||||
import json
|
||||
import signal
|
||||
import re
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from urllib.error import HTTPError, URLError
|
||||
|
||||
# Updated color codes with simpler separator
|
||||
COLORS = {
|
||||
'reset': '\033[0m',
|
||||
'bold': '\033[1m',
|
||||
'red': '\033[91m',
|
||||
'green': '\033[92m',
|
||||
'yellow': '\033[93m',
|
||||
'header': '\033[94m' # Simpler header color
|
||||
}
|
||||
|
||||
def colorize(text, color):
|
||||
if not hasattr(colorize, 'is_tty'):
|
||||
colorize.is_tty = __import__('sys').stdout.isatty()
|
||||
return f"{COLORS[color]}{text}{COLORS['reset']}" if colorize.is_tty else text
|
||||
|
||||
signal.signal(signal.SIGINT, lambda s, f: exit(1))
|
||||
|
||||
REQUEST_HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) checkpkg/1.0',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
PM_MAPPINGS = {
|
||||
'apt': ['debian_', 'ubuntu_'],
|
||||
'dnf': ['fedora_'],
|
||||
'pacman': ['arch'],
|
||||
'aur': ['aur'],
|
||||
'apk': ['alpine_'],
|
||||
'zypper': ['opensuse_']
|
||||
}
|
||||
|
||||
REPO_FORMATS = {
|
||||
'debian_': "Debian {}",
|
||||
'ubuntu_': "Ubuntu {}",
|
||||
'fedora_': "Fedora {}",
|
||||
'arch': "Arch",
|
||||
'aur': "AUR",
|
||||
'alpine_': "Alpine {}",
|
||||
'opensuse_': "openSUSE {}"
|
||||
}
|
||||
|
||||
def version_key(version):
|
||||
"""Create a sorting key for version comparison"""
|
||||
return [
|
||||
(0, int(part)) if part.isdigit() else (1, part.lower())
|
||||
for part in re.findall(r'(\d+|\D+)', version)
|
||||
]
|
||||
|
||||
def get_package_manager(repo):
|
||||
for pm, patterns in PM_MAPPINGS.items():
|
||||
if any(repo.startswith(p) for p in patterns):
|
||||
return pm
|
||||
return None
|
||||
|
||||
def format_repository(repo):
|
||||
for pattern, fmt in REPO_FORMATS.items():
|
||||
if repo.startswith(pattern):
|
||||
parts = repo.split('_')
|
||||
return fmt.format(parts[1] if len(parts) > 1 else '')
|
||||
return repo
|
||||
|
||||
def fetch_package_data(package):
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
f'https://repology.org/api/v1/project/{package}',
|
||||
headers=REQUEST_HEADERS
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=10) as response:
|
||||
return json.load(response)
|
||||
except HTTPError as e:
|
||||
if e.code == 403:
|
||||
print(colorize(f"Error: Repology blocked the request for {package} (try again later)", 'red'))
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Package search tool')
|
||||
parser.add_argument('--all', action='store_true')
|
||||
parser.add_argument('--apt', action='store_true')
|
||||
parser.add_argument('--dnf', action='store_true')
|
||||
parser.add_argument('--pacman', action='store_true')
|
||||
parser.add_argument('--apk', action='store_true')
|
||||
parser.add_argument('--zypper', action='store_true')
|
||||
parser.add_argument('--aur', action='store_true')
|
||||
parser.add_argument('packages', nargs='+')
|
||||
args = parser.parse_args()
|
||||
|
||||
selected_pms = [pm for pm, flag in [
|
||||
('apt', args.apt or args.all),
|
||||
('dnf', args.dnf or args.all),
|
||||
('pacman', args.pacman or args.all),
|
||||
('apk', args.apk or args.all),
|
||||
('zypper', args.zypper or args.all),
|
||||
('aur', args.aur or args.all)
|
||||
] if flag]
|
||||
|
||||
if not selected_pms:
|
||||
print(colorize("Error: No package managers selected", 'red'))
|
||||
return
|
||||
|
||||
results = {}
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = {executor.submit(fetch_package_data, pkg): pkg for pkg in args.packages}
|
||||
for future in as_completed(futures):
|
||||
pkg = futures[future]
|
||||
try:
|
||||
data = future.result()
|
||||
results[pkg] = data or []
|
||||
except Exception as e:
|
||||
print(colorize(f"Error processing {pkg}: {str(e)}", 'red'))
|
||||
results[pkg] = []
|
||||
|
||||
output = {}
|
||||
for pkg, entries in results.items():
|
||||
pm_versions = {pm: {'version': '', 'repos': set(), 'key': []} for pm in selected_pms}
|
||||
|
||||
for entry in entries:
|
||||
repo = entry.get('repo', '')
|
||||
version = entry.get('version', 'N/A')
|
||||
pm = get_package_manager(repo)
|
||||
|
||||
if pm in selected_pms and version != 'N/A':
|
||||
repo_fmt = format_repository(repo)
|
||||
current_key = version_key(version)
|
||||
stored = pm_versions[pm]
|
||||
|
||||
if not stored['key'] or current_key > stored['key']:
|
||||
stored['version'] = version
|
||||
stored['repos'] = {repo_fmt}
|
||||
stored['key'] = current_key
|
||||
elif current_key == stored['key']:
|
||||
stored['repos'].add(repo_fmt)
|
||||
|
||||
output[pkg] = {}
|
||||
for pm in selected_pms:
|
||||
data = pm_versions[pm]
|
||||
if data['version']:
|
||||
repos = ', '.join(sorted(data['repos']))
|
||||
output[pkg][pm] = f"{data['version']} ({repos})"
|
||||
else:
|
||||
output[pkg][pm] = 'Not found'
|
||||
|
||||
headers = ['Package'] + selected_pms
|
||||
col_widths = [len(h) for h in headers]
|
||||
|
||||
for pkg in args.packages:
|
||||
col_widths[0] = max(col_widths[0], len(pkg))
|
||||
for i, pm in enumerate(selected_pms, 1):
|
||||
col_widths[i] = max(col_widths[i], len(output.get(pkg, {}).get(pm, '')))
|
||||
|
||||
header_row = [colorize(h.ljust(w), 'header') for h, w in zip(headers, col_widths)]
|
||||
header_line = ' | '.join(header_row)
|
||||
print(header_line)
|
||||
|
||||
# Simplified single-line separator without color
|
||||
if colorize.is_tty:
|
||||
print('-' * (sum(col_widths) + 3 * (len(headers) - 1)))
|
||||
else:
|
||||
print('-' * (sum(col_widths) + 3 * (len(headers) - 1)))
|
||||
|
||||
# Print rows
|
||||
for pkg in args.packages:
|
||||
row = [colorize(pkg.ljust(col_widths[0]), 'bold')]
|
||||
versions = output.get(pkg, {pm: 'Not found' for pm in selected_pms})
|
||||
|
||||
for pm in selected_pms:
|
||||
version = versions.get(pm, 'Not found')
|
||||
color = 'green' if version != 'Not found' else 'red'
|
||||
if 'AUR' in version:
|
||||
color = 'yellow'
|
||||
row.append(colorize(version.ljust(col_widths[headers.index(pm)]), color))
|
||||
|
||||
print(' | '.join(row))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
76
dev/fonts.py
Executable file
76
dev/fonts.py
Executable file
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from colorama import init, Fore, Style
|
||||
import requests
|
||||
|
||||
# Initialize colorama
|
||||
init(autoreset=True)
|
||||
|
||||
# List of font repositories
|
||||
FONT_REPOS = {
|
||||
"JetBrainsMono": "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/JetBrainsMono.zip",
|
||||
"CaskaydiaCove": "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/CascadiaCode.zip",
|
||||
# Add more repositories here
|
||||
}
|
||||
|
||||
def display_menu(options, existing_fonts):
|
||||
print(Fore.CYAN + "Select Font Repositories to Download:")
|
||||
for i, option in enumerate(options, 1):
|
||||
icon = Fore.GREEN + "✓" if option in existing_fonts else Fore.RED + " "
|
||||
print(f"{i}. {option} {icon}")
|
||||
print(Fore.YELLOW + "0. Exit")
|
||||
|
||||
def get_user_selection(options):
|
||||
selected_indices = []
|
||||
while True:
|
||||
try:
|
||||
choices = input(Fore.YELLOW + "Enter the numbers of your choices separated by spaces (q to quit): ")
|
||||
if choices.strip().lower() == "q":
|
||||
break
|
||||
indices = [int(choice.strip()) - 1 for choice in choices.split() if choice.strip().isdigit()]
|
||||
for index in indices:
|
||||
if 0 <= index < len(options):
|
||||
selected_indices.append(index)
|
||||
else:
|
||||
print(Fore.RED + f"Invalid choice: {index + 1}. Please try again.")
|
||||
except ValueError:
|
||||
print(Fore.RED + "Invalid input. Please enter numbers separated by spaces.")
|
||||
return selected_indices
|
||||
|
||||
def download_font(url, download_path):
|
||||
response = requests.get(url)
|
||||
with open(download_path, 'wb') as file:
|
||||
file.write(response.content)
|
||||
|
||||
def clone_repos(selected_repos, base_clone_directory):
|
||||
with ThreadPoolExecutor(max_workers=4) as executor:
|
||||
future_to_repo = {
|
||||
executor.submit(download_font, FONT_REPOS[repo], os.path.join(base_clone_directory, f"{repo}.zip")): repo
|
||||
for repo in selected_repos
|
||||
}
|
||||
for future in as_completed(future_to_repo):
|
||||
repo = future_to_repo[future]
|
||||
try:
|
||||
future.result()
|
||||
print(Fore.GREEN + f"Successfully downloaded {repo}")
|
||||
except Exception as e:
|
||||
print(Fore.RED + f"Failed to download {repo}: {e}")
|
||||
|
||||
def check_existing_fonts(clone_directory):
|
||||
return {repo for repo in FONT_REPOS if os.path.exists(os.path.join(clone_directory, f"{repo}.zip"))}
|
||||
|
||||
def main():
|
||||
base_clone_directory = os.path.expanduser("~/.local/share/fonts/")
|
||||
os.makedirs(base_clone_directory, exist_ok=True)
|
||||
existing_fonts = check_existing_fonts(base_clone_directory)
|
||||
options = list(FONT_REPOS.keys())
|
||||
display_menu(options, existing_fonts)
|
||||
selected_indices = get_user_selection(options)
|
||||
selected_repos = [options[i] for i in selected_indices if options[i] not in existing_fonts]
|
||||
clone_repos(selected_repos, base_clone_directory)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue