[arch] improvement: suggestions available for repository packages

This commit is contained in:
Vinicius Moreira
2022-05-20 17:17:54 -03:00
parent dbef9a8964
commit fbd98d8b31
16 changed files with 446 additions and 38 deletions

View File

@@ -2,9 +2,10 @@ import logging
import os
import re
import shutil
import traceback
from io import StringIO
from threading import Thread
from typing import List, Set, Tuple, Dict, Iterable, Optional
from typing import List, Set, Tuple, Dict, Iterable, Optional, Any
from colorama import Fore
@@ -17,7 +18,7 @@ RE_DEPS = re.compile(r'[\w\-_]+:[\s\w_\-.]+\s+\[\w+]')
RE_OPTDEPS = re.compile(r'[\w._\-]+\s*:')
RE_DEP_NOTFOUND = re.compile(r'error:.+\'(.+)\'')
RE_DEP_OPERATORS = re.compile(r'[<>=]')
RE_INSTALLED_FIELDS = re.compile(r'(Name|Description|Version|Install Date|Validated By)\s*:\s*(.+)')
RE_REPOSITORY_FIELDS = re.compile(r'(Repository|Name|Description|Version|Install Date|Validated By)\s*:\s*(.+)')
RE_INSTALLED_SIZE = re.compile(r'Installed Size\s*:\s*([0-9,.]+)\s(\w+)\n?', re.IGNORECASE)
RE_DOWNLOAD_SIZE = re.compile(r'Download Size\s*:\s*([0-9,.]+)\s(\w+)\n?', re.IGNORECASE)
RE_UPDATE_REQUIRED_FIELDS = re.compile(r'(\bProvides\b|\bInstalled Size\b|\bConflicts With\b)\s*:\s(.+)\n')
@@ -92,23 +93,31 @@ def check_installed(pkg: str) -> bool:
return bool(res)
def _fill_ignored(res: dict):
res['pkgs'] = list_ignored_packages()
def fill_ignored_packages(output: Set[str]):
output.update(list_ignored_packages())
def map_installed(names: Optional[Iterable[str]] = None) -> Dict[str, Dict[str, str]]:
ignored = {}
thread_ignored = Thread(target=_fill_ignored, args=(ignored,), daemon=True)
thread_ignored.start()
def map_packages(names: Optional[Iterable[str]] = None, remote: bool = False, signed: bool = True,
not_signed: bool = True, skip_ignored: bool = False) -> Dict[str, Dict[str, Dict[str, str]]]:
if not signed and not not_signed:
return {}
allinfo = run_cmd('pacman -Qi{}'.format(' ' + ' '.join(names) if names else ''), print_error=False)
ignored, thread_ignored = None, None
if not skip_ignored:
ignored = set()
thread_ignored = Thread(target=fill_ignored_packages, args=(ignored,), daemon=True)
thread_ignored.start()
allinfo = run_cmd(f"pacman -{'S' if remote else 'Q'}i {' '.join(names) if names else ''}", print_error=False)
pkgs = {'signed': {}, 'not_signed': {}}
current_pkg = {}
if allinfo:
for idx, field_tuple in enumerate(RE_INSTALLED_FIELDS.findall(allinfo)):
if field_tuple[0].startswith('N'):
for idx, field_tuple in enumerate(RE_REPOSITORY_FIELDS.findall(allinfo)):
if field_tuple[0].startswith('R'):
current_pkg['repository'] = field_tuple[1].strip()
elif field_tuple[0].startswith('N'):
current_pkg['name'] = field_tuple[1].strip()
elif field_tuple[0].startswith('Ve'):
current_pkg['version'] = field_tuple[1].strip()
@@ -117,25 +126,25 @@ def map_installed(names: Optional[Iterable[str]] = None) -> Dict[str, Dict[str,
elif field_tuple[0].startswith('I'):
current_pkg['install_date'] = field_tuple[1].strip()
elif field_tuple[0].startswith('Va'):
if field_tuple[1].strip().lower() == 'none':
if not_signed and field_tuple[1].strip().lower() == 'none':
pkgs['not_signed'][current_pkg['name']] = current_pkg
del current_pkg['name']
else:
elif signed:
pkgs['signed'][current_pkg['name']] = current_pkg
del current_pkg['name']
current_pkg = {}
if pkgs['signed'] or pkgs['not_signed']:
if thread_ignored and (pkgs['signed'] or pkgs['not_signed']):
thread_ignored.join()
if ignored['pkgs']:
if ignored:
to_del = set()
for key in ('signed', 'not_signed'):
if pkgs.get(key):
for pkg in pkgs[key].keys():
if pkg in ignored['pkgs']:
if pkg in ignored:
to_del.add(pkg)
for pkg in to_del:
@@ -219,20 +228,23 @@ def sign_key(key: str, root_password: Optional[str]) -> SystemProcess:
def list_ignored_packages(config_path: str = '/etc/pacman.conf') -> Set[str]:
pacman_conf = new_subprocess(['cat', config_path])
ignored = set()
grep = new_subprocess(['grep', '-Eo', r'\s*#*\s*ignorepkg\s*=\s*.+'], stdin=pacman_conf.stdout)
for o in grep.stdout:
if o:
line = o.decode().strip()
try:
pacman_conf = new_subprocess(['cat', config_path])
grep = new_subprocess(['grep', '-Eo', r'\s*#*\s*ignorepkg\s*=\s*.+'], stdin=pacman_conf.stdout)
for o in grep.stdout:
if o:
line = o.decode().strip()
if not line.startswith('#'):
ignored.add(line.split('=')[1].strip())
if not line.startswith('#'):
ignored.add(line.split('=')[1].strip())
pacman_conf.terminate()
grep.terminate()
return ignored
pacman_conf.terminate()
grep.terminate()
return ignored
except:
traceback.print_exc()
return ignored
def check_missing(names: Set[str]) -> Set[str]:
@@ -1037,3 +1049,24 @@ def find_one_match(name: str) -> Optional[str]:
if matches and len(matches) == 1:
return matches[0]
def map_available_packages() -> Optional[Dict[str, Any]]:
output = run_cmd('pacman -Sl')
if output:
res = dict()
for line in output.split('\n'):
line_strip = line.strip()
if line_strip:
package_data = line.split(' ')
if len(package_data) >= 3:
pkgname = package_data[1].strip()
if pkgname:
res[pkgname] = {'v': package_data[2].strip(),
'r': package_data[0].strip(),
'i': len(package_data) == 4 and 'installed' in package_data[3]}
return res