aur/yauri
2026-02-08 10:20:25 -05:00

325 lines
12 KiB
Python
Executable file

#!/usr/bin/python3
## CODE TAKEN FROM github:peakwinter/python-pacman
## DEPENDS ON python-requests, git, pacman-contrib, python
## yauri, the gayest AUR helper ever, all fitting into 1 file.
import requests
import argparse
import os
import subprocess
import shlex
import colorama
VERSION = "1.0"
AUR_RPC_URL = f"https://aur.archlinux.org/rpc/?v=5"
SCRIPTDIR = os.path.dirname(os.path.realpath(__file__))
lang_en_CA = {
"UPDATE_FAILED": "Updating in Pacman has failed.",
"START_AUR_UPDATE": "Beginning update of AUR packages.",
"NO_AUR_PACKAGES": "No AUR packages installed!",
"INSTALLING_AUR_UPDATES": "Installing updates from AUR...",
"PACKAGE_NOT_FOUND": "Package not found!",
"UP_TO_DATE": "AUR packages up to date!",
"REPOSITORY": "Repository",
"NAME": "Name",
"VERSION": "Version",
"DESCRIPTION": "Description",
"URL": "URL",
"LICENSES": "Licenses",
"OUTDATED": "Is outdated?",
"SUBMITTER": "Submitter",
"MAINTAINER": "Maintainer",
"MAKE_DEPENDS_ON": "Make depends on",
"DEPENDS_ON": "Depends on",
"OPT_DEPENDS": "Optionally depends",
"POPULARITY": "Popularity",
"DESC_PACKAGEMANAGER": "yauri, the gayest aur helper ever, all fitting into 1 file.",
"UPDATE_PACKAGES": "Update package(s)",
"INSTALL_PACKAGE": "Install package(s)",
"PACKAGES_TO_INSTALL": "Packages to install",
"REMOVE_PACKAGE": "Remove package(s)",
"PACKAGES_TO_REMOVE": "Packages to remove",
"SEARCH_PACKAGE": "Search for packages",
"PACKAGES_TO_SEARCH_FOR": "Packages to search for",
"INFO_PACKAGE": "Get info about a package",
"INFO_ABOUT_PACKAGES": "Package to get info about",
"AUTOREMOVE": "Remove orphaned packages.",
"CACHECLEAR": "Clear cache.",
"DISPLAY_VERSION_AND_EXIT": "Display version and exit.",
"AUR_PACKAGES_REMOVED": "Cached AUR packages removed."
}
languages = {
"en_CA": lang_en_CA
}
cur_lang: dict
## UTILITY FUNCTIONS
def load_language():
global cur_lang
lang_name = os.getenv("LANG")
if lang_name not in languages:
cur_lang = languages["en_CA"]
else:
cur_lang = languages[lang_name]
def get_installed_aur_packages():
"""Lists every package. (Not from official repos**)"""
aur_packages = list()
result = pacman("-Qm")
output = result["stdout"]
if result["code"] != 0:
return None
packages = output.splitlines()
nonstandard_packages = [pkg.split()[0] for pkg in packages]
for pkg in nonstandard_packages:
if is_aur(pkg):
aur_packages.append(pkg)
return aur_packages
def pacman(flags, pkgs=[], eflgs=[], sudo=False, interactive=False):
"""Subprocess wrapper, get all data"""
if not pkgs:
if sudo:
cmd = ["sudo", "pacman", "--noconfirm", flags]
else:
cmd = ["pacman", "--noconfirm", flags]
elif type(pkgs) == list:
if sudo:
cmd = ["sudo", "pacman", "--noconfirm", flags]
else:
cmd = ["pacman", "--noconfirm", flags]
cmd += [shlex.quote(s) for s in pkgs]
else:
if sudo:
cmd = ["sudo", "pacman", "--noconfirm", flags, pkgs]
else:
cmd = ["pacman", "--noconfirm", flags, pkgs]
if eflgs and any(eflgs):
eflgs = [x for x in eflgs if x]
cmd += eflgs
if interactive == False:
p = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
data = {"code": p.returncode, "stdout": p.stdout.decode(),
"stderr": p.stderr.decode()}
else:
p = subprocess.run(cmd)
data = {"code": p.returncode}
return data
def is_aur(package):
'''
Return True if the given package is an AUR package.
'''
response = requests.get(AUR_RPC_URL + "&type=search&arg=" + package)
if response.status_code == 200:
result = response.json()
if result['resultcount'] > 0:
return True
return False
def is_pacman(package):
# Run the pacman search command
result = subprocess.run(
['pacman', '-Si', package],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode == 0:
return True
else:
return False
## MAIN COMMANDLINE FUNCTIONS
def search(query):
"""
Searches for packages in the AUR and Pacman.
:param query: Search query
"""
# Search in the AUR
url = f"{AUR_RPC_URL}&type=search&arg={query}"
response = requests.get(url)
if response.status_code == 200:
aur_results = response.json().get('results', [])
else:
aur_results = None
# Pacman search
pacman_search = pacman("-Ss", query)
lines = pacman_search["stdout"].splitlines()
for result in aur_results:
lines.append(f"{colorama.Fore.BLUE}aur{colorama.Fore.RESET}/{result["Name"]} {result["Version"]}")
lines.append(f" {result["Description"]}")
for line in lines:
print(line)
def update():
output = pacman("-Syu", sudo=True, interactive=True)
output_Fy = pacman("-Fy", sudo=True, interactive=True)
if output["code"] != 0 or output_Fy["code"] != 0:
print(colorama.Fore.RED + cur_lang["UPDATE_FAILED"] + colorama.Fore.RESET)
exit(1)
return
print(cur_lang["START_AUR_UPDATE"])
installed_aur_packages = get_installed_aur_packages()
if installed_aur_packages == None:
print(cur_lang["NO_AUR_PACKAGES"])
exit(1)
return
aur_info_url = f"{AUR_RPC_URL}&type=info&arg[]="
for package in installed_aur_packages:
aur_info_url += f"{package}&arg[]="
response = requests.get(aur_info_url)
updates = []
if response.status_code == 200:
result = response.json()
for pkg in result['results']:
local_version = pacman('-Qm', pkg['Name'])["stdout"].split()[1]
if pkg['Version'] != local_version:
updates.append(pkg['Name'])
if updates != []:
print(cur_lang["INSTALLING_AUR_UPDATES"])
install(updates)
else:
print(colorama.Fore.LIGHTGREEN_EX + cur_lang["UP_TO_DATE"] + colorama.Fore.RESET)
def install(package):
pacman_packages = list()
aur_packages = list()
list_of_pkg = shlex.split(package)
for pkg in list_of_pkg:
if is_pacman(pkg):
pacman_packages.append(pkg)
elif is_aur(pkg):
aur_packages.append(pkg)
else:
print(colorama.Fore.RED + cur_lang["PACKAGE_NOT_FOUND"] + colorama.Fore.RESET)
exit(1)
return
if len(pacman_packages) != 0:
pacman("-Sy", pacman_packages, sudo=True, interactive=True)
if len(aur_packages) != 0:
for aur_package in aur_packages:
if os.path.exists(os.path.expanduser(f"~/.cache/yauri/{aur_package}")):
# I don't wanna hear a word about it.
subprocess.run(shlex.split(f"rm -rf {os.path.expanduser(f"~/.cache/yauri/{aur_package}")}"))
subprocess.run(shlex.split(f"git clone https://aur.archlinux.org/{aur_package}.git {os.path.expanduser(f"~/.cache/yauri/{aur_package}")}"))
subprocess.run(shlex.split(f"makepkg -sCci"), cwd=os.path.expanduser(f"~/.cache/yauri/{aur_package}"))
else:
print(colorama.Fore.RED + cur_lang["PACKAGE_NOT_FOUND"] + colorama.Fore.RESET)
exit(1)
return
def remove(packages):
pacman("-Rc", shlex.split(packages), sudo=True)
def info(package):
if is_pacman(package):
pacman("-Si", package, interactive=True)
elif is_aur(package):
aur_info_url = f"{AUR_RPC_URL}&type=info&arg[]={package}"
response = requests.get(aur_info_url)
if response.status_code == 200:
result = response.json()
package_data = result["results"][0]
print(f"{cur_lang["REPOSITORY"]} : {colorama.Fore.BLUE}aur{colorama.Fore.RESET}")
print(f"{cur_lang["NAME"]} : {package}")
print(f"{cur_lang["VERSION"]} : {package_data["Version"] if "Version" in package_data else None}")
print(f"{cur_lang["DESCRIPTION"]} : {package_data["Description"] if "Description" in package_data else None}")
print(f"{cur_lang["URL"]} : {package_data["URL"] if "URL" in package_data else None}")
print(f"{cur_lang["LICENSES"]} : {package_data["License"] if "License" in package_data else None}")
print(f"{cur_lang["OUTDATED"]} : {package_data["OutOfDate"] if "OutOfDate" in package_data else None}")
print(f"{cur_lang["SUBMITTER"]} : {package_data["Submitter"] if "Submitter" in package_data else None}")
print(f"{cur_lang["MAINTAINER"]} : {package_data["Maintainer"] if "Maintainer" in package_data else None}")
print(f"{cur_lang["MAKE_DEPENDS_ON"]} : {package_data["MakeDepends"] if "MakeDepends" in package_data else None}")
print(f"{cur_lang["DEPENDS_ON"]} : {package_data["Depends"] if "Depends" in package_data else None}")
print(f"{cur_lang["OPT_DEPENDS"]} : {package_data["OptDepends"] if "OptDepends" in package_data else None}")
print(f"{cur_lang["POPULARITY"]} : {package_data["Popularity"] if "Popularity" in package_data else None}")
else:
print(colorama.Fore.RED + cur_lang["PACKAGE_NOT_FOUND"] + colorama.Fore.RESET)
def cacheclear():
os.system("bash -c 'sudo paccache -rk0'")
pkgs = os.listdir(f"{os.path.expanduser('~')}/.cache/yauri/")
for pkg in pkgs:
os.system(f"rm -rf {os.path.expanduser('~')}/.cache/yauri/{pkg}")
print(f"{len(pkgs)} {colorama.Fore.BLUE}{cur_lang["AUR_PACKAGES_REMOVED"]}{colorama.Fore.RESET}")
def main():
colorama.init()
load_language()
parser = argparse.ArgumentParser(description=cur_lang["DESC_PACKAGEMANAGER"])
parser.add_argument('-v', '--version', action='store_true', help=cur_lang["DISPLAY_VERSION_AND_EXIT"])
subparsers = parser.add_subparsers(dest='command', help='commands')
# Update command
subparsers.add_parser('update', help=cur_lang["UPDATE_PACKAGES"])
# Cacheclear command
subparsers.add_parser('clearcache', help=cur_lang["CACHECLEAR"])
# Install command
install_parser = subparsers.add_parser('install', help=cur_lang["INSTALL_PACKAGE"])
install_parser.add_argument('package', type=str, nargs="+", help=cur_lang["PACKAGES_TO_INSTALL"])
# Remove command
remove_parser = subparsers.add_parser('remove', help=cur_lang["REMOVE_PACKAGE"])
remove_parser.add_argument('package', type=str, nargs="+", help='PACKAGES_TO_REMOVE')
# Search command
search_parser = subparsers.add_parser('search', help=cur_lang["SEARCH_PACKAGE"])
search_parser.add_argument('package', type=str, help=cur_lang["PACKAGES_TO_SEARCH_FOR"])
# Info command
info_parser = subparsers.add_parser('info', help=cur_lang["INFO_PACKAGE"])
info_parser.add_argument('package', type=str, help=cur_lang["INFO_ABOUT_PACKAGES"])
# Autoremove command
auto_remove_parser = subparsers.add_parser('autoremove', help=cur_lang["AUTOREMOVE"])
args = parser.parse_args()
try:
if args.version:
print(VERSION)
exit(0)
if args.command == 'update':
update()
elif args.command == 'clearcache':
cacheclear()
elif args.command == 'install':
install(" ".join(args.package))
elif args.command == 'remove':
remove(args.package)
elif args.command == 'search':
search(args.package)
elif args.command == "info":
info(args.package)
elif args.command == "autoremove":
os.system("sudo pacman -Rns $(pacman -Qdtq)")
else:
parser.print_help()
except KeyboardInterrupt:
pass
if not os.path.exists(os.path.expanduser("~/.cache/yauri")):
os.mkdir(os.path.expanduser("~/.cache/yauri"))
if __name__ == '__main__':
main()