342 lines
9.8 KiB
Python
Executable File
342 lines
9.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from dataclasses import dataclass
|
|
from fnmatch import fnmatch
|
|
from pathlib import Path
|
|
import textwrap
|
|
import typing
|
|
|
|
|
|
@dataclass
|
|
class GappsTarget:
|
|
name: str
|
|
soong_imports: list[str]
|
|
additional_namespaces: list[str]
|
|
additional_packages: list[str]
|
|
additional_makefiles_to_inherit: list[str]
|
|
|
|
|
|
class SoongModule:
|
|
def __init__(self):
|
|
self.soong_module = type(self).__name__
|
|
|
|
@staticmethod
|
|
def _value_to_str(value: typing.Any) -> str:
|
|
match value:
|
|
case bool():
|
|
return ["false", "true"][value]
|
|
case dict():
|
|
ret = "{\n"
|
|
|
|
for key, value in value.items():
|
|
ret += f"{indent(SoongModule._prop_to_str(key, value))}\n"
|
|
|
|
ret += "}"
|
|
|
|
return ret
|
|
case list():
|
|
return f'[{", ".join([SoongModule._value_to_str(x) for x in value])}]'
|
|
case str():
|
|
return f'"{value}"'
|
|
case default:
|
|
assert False, f"Unhandled value type: {type(value)}"
|
|
|
|
@staticmethod
|
|
def _prop_to_str(key: str, value: typing.Any) -> str:
|
|
return f"{key}: {SoongModule._value_to_str(value)},"
|
|
|
|
def _to_blueprint(self, props: dict) -> str:
|
|
ret = f"{self.soong_module} {{\n"
|
|
|
|
for key, value in props.items():
|
|
ret += f"{indent(SoongModule._prop_to_str(key, value))}\n"
|
|
|
|
ret += "}"
|
|
|
|
return ret
|
|
|
|
|
|
class SoongPrebuilt(SoongModule):
|
|
def __init__(self, install_path: str, flags: dict):
|
|
SoongModule.__init__(self)
|
|
|
|
self.name = Path(install_path).stem
|
|
self.install_path = install_path
|
|
self.src = f"proprietary/{install_path}"
|
|
self.flags = flags
|
|
|
|
def _has_flag(self, key: str) -> bool:
|
|
return key in self.flags
|
|
|
|
def _flag(self, key: str) -> str | None:
|
|
return self.flags.get(key, None)
|
|
|
|
def _to_blueprint(self, props: dict) -> str:
|
|
partition, _ = self.install_path.split("/", maxsplit=1)
|
|
|
|
match partition:
|
|
case "system":
|
|
pass
|
|
case "product":
|
|
props["product_specific"] = True
|
|
case "system_ext":
|
|
props["system_ext_specific"] = True
|
|
case _:
|
|
assert False, f"Unhandled partition: {partition}"
|
|
|
|
return super()._to_blueprint(props)
|
|
|
|
|
|
class android_app_import(SoongPrebuilt):
|
|
def to_blueprint(self) -> str:
|
|
props = {
|
|
"name": self.name,
|
|
"owner": "gapps",
|
|
"apk": self.src,
|
|
"overrides": [self._flag("OVERRIDES")],
|
|
"preprocessed": True,
|
|
"presigned": True,
|
|
"dex_preopt": {
|
|
"enabled": False,
|
|
},
|
|
"privileged": True,
|
|
}
|
|
|
|
_, apk_dst, _ = self.install_path.split("/", maxsplit=2)
|
|
|
|
if apk_dst != "priv-app":
|
|
del props["privileged"]
|
|
|
|
if not self._has_flag("OVERRIDES"):
|
|
del props["overrides"]
|
|
|
|
if not self._has_flag("PRESIGNED"):
|
|
del props["presigned"]
|
|
|
|
return self._to_blueprint(props)
|
|
|
|
|
|
class cc_prebuilt_library_shared(SoongPrebuilt):
|
|
def to_blueprint(self) -> str:
|
|
props = {
|
|
"name": self.name,
|
|
"srcs": [self.src],
|
|
"prefer": True,
|
|
}
|
|
|
|
return self._to_blueprint(props)
|
|
|
|
|
|
class dex_import(SoongPrebuilt):
|
|
def to_blueprint(self) -> str:
|
|
props = {
|
|
"name": self.name,
|
|
"owner": "gapps",
|
|
"jars": [self.src],
|
|
}
|
|
|
|
return self._to_blueprint(props)
|
|
|
|
|
|
class prebuilt_etc(SoongPrebuilt):
|
|
def __init__(self, install_path: str, flags: dict):
|
|
super().__init__(install_path, flags)
|
|
|
|
self.name += Path(self.install_path).suffix
|
|
|
|
def to_blueprint(self) -> str:
|
|
props = {
|
|
"name": self.name,
|
|
"src": self.src,
|
|
"relative_install_path": "/".join(self.install_path.split("/")[2:-1]),
|
|
"filename_from_src": True,
|
|
}
|
|
|
|
return self._to_blueprint(props)
|
|
|
|
|
|
class soong_namespace(SoongModule):
|
|
def __init__(self, imports: list[str]):
|
|
super().__init__()
|
|
|
|
self.imports = imports
|
|
|
|
def to_blueprint(self) -> str:
|
|
props = {
|
|
"imports": self.imports,
|
|
}
|
|
|
|
if not self.imports:
|
|
del props["imports"]
|
|
|
|
return self._to_blueprint(props)
|
|
|
|
|
|
def indent(text: str) -> str:
|
|
return textwrap.indent(text, " " * 4)
|
|
|
|
|
|
def parse_proprietary_file(line: str) -> SoongPrebuilt:
|
|
# Format: ORIG_PATH:INSTALL_PATH;FLAGS|SHA1
|
|
|
|
if "|" in line:
|
|
line, file_hash = line.split("|")
|
|
else:
|
|
file_hash = None
|
|
|
|
if ";" in line:
|
|
line, flags_str = line.split(";", maxsplit=1)
|
|
flags = {}
|
|
for flag in flags_str.split(";"):
|
|
if "=" in flag:
|
|
key, value = flag.split("=", maxsplit=1)
|
|
else:
|
|
key = flag
|
|
value = None
|
|
flags[key] = value
|
|
else:
|
|
flags = {}
|
|
|
|
if ":" in line:
|
|
line, install_path = line.split(":")
|
|
else:
|
|
install_path = line
|
|
|
|
for pattern, blob_type in {
|
|
"*.apk": android_app_import,
|
|
"*.jar": dex_import,
|
|
"*.so": cc_prebuilt_library_shared,
|
|
"*/etc/*.*": prebuilt_etc,
|
|
}.items():
|
|
if fnmatch(install_path, pattern):
|
|
return blob_type(install_path, flags)
|
|
else:
|
|
assert False, f"Unhandled install path: {install_path}"
|
|
|
|
|
|
def parse_proprietary_files(path: str) -> list:
|
|
packages = []
|
|
|
|
if Path(path).is_file():
|
|
for line in open(path).readlines():
|
|
line = line.strip()
|
|
|
|
if not line:
|
|
continue
|
|
|
|
if package := parse_proprietary_file(line):
|
|
packages.append(package)
|
|
|
|
return sorted(packages, key=lambda x: (x.soong_module, x.name))
|
|
|
|
|
|
def generate(targets: list[GappsTarget]) -> None:
|
|
for target in targets:
|
|
packages = parse_proprietary_files(f"proprietary-files-{target.name}.txt")
|
|
packages_nongrouper = parse_proprietary_files(
|
|
f"proprietary-files-{target.name}-nongrouper.txt"
|
|
)
|
|
packages_tangorpro = parse_proprietary_files(
|
|
f"proprietary-files-{target.name}-tangorpro.txt"
|
|
)
|
|
packages_all = sorted(
|
|
packages + packages_nongrouper + packages_tangorpro,
|
|
key=lambda x: (x.soong_module, x.name),
|
|
)
|
|
|
|
with open(f"{target.name}/Android.bp", "+wt") as f:
|
|
f.write("// Automatically generated file. DO NOT MODIFY\n")
|
|
f.write("\n")
|
|
|
|
f.write(soong_namespace(target.soong_imports).to_blueprint())
|
|
f.write("\n")
|
|
|
|
for package in packages_all:
|
|
f.write("\n")
|
|
f.write(package.to_blueprint())
|
|
f.write("\n")
|
|
|
|
with open(f"{target.name}/BoardConfigVendor.mk", "+wt") as f:
|
|
f.write("# Automatically generated file. DO NOT MODIFY\n")
|
|
f.write("#\n")
|
|
|
|
with open(f"{target.name}/{target.name}-vendor.mk", "+wt") as f:
|
|
f.write("# Automatically generated file. DO NOT MODIFY\n")
|
|
f.write("#\n")
|
|
|
|
def write_list(var: str, items: list[str]):
|
|
f.write(f"{var} += \\\n")
|
|
f.write(" \\\n".join([indent(x) for x in items]))
|
|
f.write("\n")
|
|
|
|
f.write("\n")
|
|
write_list("PRODUCT_SOONG_NAMESPACES", [f"$(LOCAL_PATH)"])
|
|
|
|
if packages:
|
|
f.write("\n")
|
|
write_list("PRODUCT_PACKAGES", [x.name for x in packages])
|
|
|
|
if packages_nongrouper:
|
|
f.write("\n")
|
|
f.write("ifeq ($(TARGET_IS_GROUPER),)\n")
|
|
write_list("PRODUCT_PACKAGES", [x.name for x in packages_nongrouper])
|
|
f.write("endif\n")
|
|
|
|
if packages_tangorpro:
|
|
f.write("\n")
|
|
f.write("ifneq ($(filter %tangorpro,$(TARGET_PRODUCT)),)\n")
|
|
write_list("PRODUCT_PACKAGES", [x.name for x in packages_tangorpro])
|
|
f.write("endif\n")
|
|
|
|
if target.additional_namespaces:
|
|
f.write("\n")
|
|
write_list("PRODUCT_SOONG_NAMESPACES", target.additional_namespaces)
|
|
|
|
if target.additional_packages:
|
|
f.write("\n")
|
|
write_list("PRODUCT_PACKAGES", target.additional_packages)
|
|
|
|
for path in target.additional_makefiles_to_inherit:
|
|
f.write("\n")
|
|
f.write(f"$(call inherit-product, {path})\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
generate(
|
|
[
|
|
GappsTarget(
|
|
name="common",
|
|
soong_imports=[],
|
|
additional_namespaces=["vendor/gapps/overlay"],
|
|
additional_packages=[x.name for x in Path("overlay").glob("*Overlay")],
|
|
additional_makefiles_to_inherit=[],
|
|
),
|
|
GappsTarget(
|
|
name="arm",
|
|
soong_imports=["vendor/gapps/common"],
|
|
additional_namespaces=[],
|
|
additional_packages=[],
|
|
additional_makefiles_to_inherit=[
|
|
"vendor/gapps/common/common-vendor.mk",
|
|
],
|
|
),
|
|
GappsTarget(
|
|
name="arm64",
|
|
soong_imports=["vendor/gapps/common"],
|
|
additional_namespaces=[],
|
|
additional_packages=[],
|
|
additional_makefiles_to_inherit=[
|
|
"vendor/gapps/common/common-vendor.mk",
|
|
],
|
|
),
|
|
GappsTarget(
|
|
name="x86_64",
|
|
soong_imports=["vendor/gapps/common"],
|
|
additional_namespaces=[],
|
|
additional_packages=[],
|
|
additional_makefiles_to_inherit=[
|
|
"vendor/gapps/common/common-vendor.mk",
|
|
],
|
|
),
|
|
]
|
|
)
|