Files
bearhub/bauh/gems/arch/disk.py
2022-12-12 07:44:27 -03:00

129 lines
4.6 KiB
Python

import json
import os
import re
from pathlib import Path
from typing import List, Dict, Tuple, Optional, Callable
from bauh.gems.arch import pacman
from bauh.gems.arch.model import ArchPackage
RE_DESKTOP_ENTRY = re.compile(r'[\n^](Exec|Icon|NoDisplay)\s*=\s*(.+)')
RE_CLEAN_NAME = re.compile(r'[+*?%]')
def write_several(pkgs: Dict[str, ArchPackage], overwrite: bool = True, maintainer: str = None, after_desktop_files: Optional[Callable] = None, after_written: Optional[Callable[[str], None]] = None) -> int:
if overwrite:
to_cache = {p.name for p in pkgs.values()}
else:
to_cache = {p.name for p in pkgs.values() if not os.path.exists(p.get_disk_cache_path())}
desktop_files = pacman.map_desktop_files(*to_cache)
if after_desktop_files:
after_desktop_files()
if not desktop_files:
for pkgname in to_cache:
write(pkg=pkgs[pkgname], maintainer=maintainer, after_written=after_written)
return len(to_cache)
else:
for pkgname in to_cache:
pkgfiles = desktop_files.get(pkgname)
if not pkgfiles:
write(pkg=pkgs[pkgname], maintainer=maintainer, after_written=after_written)
else:
desktop_entry = find_best_desktop_entry(pkgname, pkgfiles)
if desktop_entry:
write(pkg=pkgs[pkgname], maintainer=maintainer, after_written=after_written,
desktop_file=desktop_entry[0], command=desktop_entry[1], icon=desktop_entry[2])
else:
write(pkg=pkgs[pkgname], maintainer=maintainer, after_written=after_written)
return len(to_cache)
def find_best_desktop_entry(pkgname: str, desktop_files: List[str]) -> Optional[Tuple[str, str, str]]:
if len(desktop_files) == 1:
exec_icon = read_desktop_exec_and_icon(pkgname, desktop_files[0])
if exec_icon:
return desktop_files[0], exec_icon[0], exec_icon[1]
else:
# trying to find the exact name match:
for dfile in desktop_files:
if dfile.endswith('{}.desktop'.format(pkgname)):
exec_icon = read_desktop_exec_and_icon(pkgname, dfile)
if exec_icon:
return dfile, exec_icon[0], exec_icon[1]
# trying to find a close name match:
clean_name = RE_CLEAN_NAME.sub('', pkgname)
for dfile in desktop_files:
if dfile.endswith('{}.desktop'.format(clean_name)):
exec_icon = read_desktop_exec_and_icon(clean_name, dfile)
if exec_icon:
return dfile, exec_icon[0], exec_icon[1]
# finding any match:
for dfile in desktop_files:
exec_icon = read_desktop_exec_and_icon(pkgname, dfile)
if exec_icon:
return dfile, exec_icon[0], exec_icon[1]
def read_desktop_exec_and_icon(pkgname: str, desktop_file: str) -> Optional[Tuple[str, str]]:
if os.path.isfile(desktop_file):
with open(desktop_file) as f:
possibilities = set()
content = f.read()
cmd, icon = None, None
for field in RE_DESKTOP_ENTRY.findall(content):
if field[0] == 'Exec':
cmd = field[1].strip().replace('"', '')
elif field[0] == 'Icon':
icon = field[1].strip()
elif field[0] == 'NoDisplay' and field[1].strip().lower() == 'true':
cmd, icon = None, None
if cmd and icon:
possibilities.add((cmd, icon))
cmd, icon = None, None
if possibilities:
if len(possibilities) == 1:
return [*possibilities][0]
else:
# trying to find the exact name x command match
for p in possibilities:
if p[0].startswith('{} '.format(pkgname)):
return p
return sorted(possibilities)[0] # returning any possibility
def write(pkg: ArchPackage, desktop_file: Optional[str] = None, command: Optional[str] = None,
icon: Optional[str] = None, maintainer: Optional[str] = None, after_written: Optional[callable] = None):
pkg.desktop_entry = desktop_file
pkg.command = command
pkg.icon_path = icon
if maintainer and not pkg.maintainer:
pkg.maintainer = maintainer
Path(pkg.get_disk_cache_path()).mkdir(parents=True, exist_ok=True)
data = pkg.get_data_to_cache()
with open(pkg.get_disk_data_path(), 'w+') as f:
f.write(json.dumps(data))
if after_written:
after_written(pkg.name)