diff --git a/packages/org.xbmc.kodi.py b/packages/org.xbmc.kodi.py index 9f240ae..bc6e30a 100644 --- a/packages/org.xbmc.kodi.py +++ b/packages/org.xbmc.kodi.py @@ -77,7 +77,7 @@ def load() -> PackageRegistry: with open(ipk_path, 'rb') as f: ipk_hash = hashlib.sha256(f.read()).hexdigest() - appinfo = ipk_file.get_appinfo(ipk_path) + control, appinfo = ipk_file.get_appinfo(ipk_path) manifest = { 'id': appinfo['id'], 'title': appinfo['title'], @@ -90,7 +90,8 @@ def load() -> PackageRegistry: 'ipkHash': { 'sha256': ipk_hash }, - 'ipkSize': os.stat(ipk_path).st_size + 'ipkSize': os.stat(ipk_path).st_size, + 'installedSize': control['installedSize'], } with cache.open_file(manifest_name, 'w') as f: json.dump(manifest, f) diff --git a/repogen/__main__.py b/repogen/__main__.py index 121278e..ad08746 100644 --- a/repogen/__main__.py +++ b/repogen/__main__.py @@ -13,11 +13,13 @@ parser.add_argument('-D', '--no-gen-details', dest='gen_details', action='store_false') parser.add_argument('-L', '--no-gen-list', dest='gen_list', action='store_false') +parser.add_argument('-p', '--packages', nargs='+', required=False) + parser.set_defaults(gen_api=True, gen_details=True, gen_list=True) args = parser.parse_args() -packages = pkg_info.list_packages(Path(args.input_dir)) +packages = pkg_info.list_packages(Path(args.input_dir), args.packages) if args.gen_api: apidata.generate(packages, Path(args.output_dir, 'api')) diff --git a/repogen/ipk_file.py b/repogen/ipk_file.py index e5117cc..4db4d12 100644 --- a/repogen/ipk_file.py +++ b/repogen/ipk_file.py @@ -1,10 +1,15 @@ import io import json -import re import tarfile -from typing import TypedDict, NotRequired +from typing import TypedDict, NotRequired, Optional import ar +from debian_parser import PackagesParser + + +class Control(TypedDict): + version: str + installedSize: Optional[int] class AppInfo(TypedDict): @@ -15,14 +20,21 @@ class AppInfo(TypedDict): appDescription: NotRequired[str] -def get_appinfo(ipk_path: str) -> AppInfo: +def get_appinfo(ipk_path: str) -> (Control, AppInfo): with open(ipk_path, 'rb') as f: archive = ar.Archive(f) control_file = io.BytesIO(archive.open('control.tar.gz', mode='rb').read()) with tarfile.open(fileobj=control_file, mode='r:gz') as control: with control.extractfile(control.getmember('control')) as cf: - package_name = re.compile(r'Package: (.+)\n').match(cf.readline().decode('utf-8')).group(1) + parser = PackagesParser(cf.read().decode('utf-8')) + control_data = {entry['tag']: entry['value'] for entry in parser.parse()[0]} + package_name = control_data['Package'] + installed_size = int(control_data['Installed-Size']) + control_info: Control = { + 'version': control_data['Version'], + 'installedSize': installed_size if installed_size > 10000 else None + } data_file = io.BytesIO(archive.open('data.tar.gz', mode='rb').read()) with tarfile.open(fileobj=data_file, mode='r:gz') as data: with data.extractfile(data.getmember(f'usr/palm/applications/{package_name}/appinfo.json')) as af: - return json.load(af) + return control_info, json.load(af) diff --git a/repogen/pkg_info.py b/repogen/pkg_info.py index 961ef6e..224e25a 100644 --- a/repogen/pkg_info.py +++ b/repogen/pkg_info.py @@ -32,10 +32,9 @@ class PackageInfo(TypedDict): lastmodified_str: str -def from_package_info_file(info_path: Path, offline=False) -> Optional[PackageInfo]: +def load_registry(info_path: Path) -> (str, PackageRegistry): extension = info_path.suffix content: PackageRegistry - print(f'Parsing package info file {info_path.name}', file=sys.stderr) if extension == '.yml': pkgid, content = parse_yml_package(info_path) elif extension == '.py': @@ -44,10 +43,16 @@ def from_package_info_file(info_path: Path, offline=False) -> Optional[PackageIn raise ValueError(f'Unrecognized info format {extension}') validator = validators.for_schema('packages/PackageInfo.json') validator.validate(content) + return pkgid, content + + +def from_package_info_file(info_path: Path, offline=False) -> Optional[PackageInfo]: + pkgid, content = load_registry(info_path) return from_package_info(pkgid, content, offline) def from_package_info(pkgid: str, content: PackageRegistry, offline=False) -> PackageInfo: + print(f'Parsing package info for {pkgid}', file=sys.stderr) manifest_url = url_fixup(content['manifestUrl']) pkginfo: PackageInfo = { 'id': pkgid, @@ -99,10 +104,20 @@ def from_package_info(pkgid: str, content: PackageRegistry, offline=False) -> Pa return pkginfo -def list_packages(pkgdir: Path, offline: bool = False) -> List[PackageInfo]: +def list_packages(pkgdir: Path, packages: Optional[List[str]] = None, offline: bool = False) -> List[PackageInfo]: paths: List[Path] = [f for f in pkgdir.iterdir() if f.is_file()] - return sorted(filter(lambda x: x, map(lambda p: from_package_info_file(p, offline), paths)), - key=lambda x: x['title']) + + def map_package_info(p: Path) -> Optional[PackageInfo]: + pkgid, content = load_registry(p) + if packages and pkgid not in packages: + return None + try: + return from_package_info(pkgid, content, offline) + except Exception as e: + print(f'Error loading package info file {p.name}: {e}', file=sys.stderr) + return None + + return sorted(filter(lambda x: x, map(map_package_info, paths)), key=lambda x: x['title']) def valid_pool(value: str) -> str: diff --git a/repogen/pkg_manifest.py b/repogen/pkg_manifest.py index 1e52ae7..f2f524a 100644 --- a/repogen/pkg_manifest.py +++ b/repogen/pkg_manifest.py @@ -29,7 +29,8 @@ class PackageManifest(TypedDict): rootRequired: NotRequired[bool | Literal['optional']] ipkUrl: str ipkHash: PackageHash - ipkSize: int + ipkSize: NotRequired[int] + installedSize: NotRequired[int] def obtain_manifest(pkgid: str, channel: str, uri: str, offline: bool = False) -> Tuple[PackageManifest, datetime]: diff --git a/requirements.txt b/requirements.txt index facf0b5..d964614 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,5 +15,6 @@ jsonschema~=4.19.1 semantic-version~=2.10.0 shellescape~=3.8.1 lxml~=4.9.2 +debian-parser~=0.1.2 git+https://github.com/Kronuz/pyScss.git@60414f5d573315a8458b5fbcdf69e5c648c44a9a#egg=pyscss git+https://github.com/webosbrew/pelican-theme-webosbrew.git@v1.0.9#egg=pelican-theme-webosbrew \ No newline at end of file