blob: ba75dc1f47ae49d50881af08fe8d776c1d235d2b [file] [log] [blame]
from absl import app
from absl import flags
import filecmp
from lxml import etree
from pathlib import Path
import shutil
FLAGS = flags.FLAGS
flags.DEFINE_string("android_root", None, "Root of android repo")
flags.DEFINE_bool("dry_run", True, "If False actually update files")
def _require_exists(a_file: Path) -> Path:
if not a_file.is_file():
raise ValueError(f"{a_file} missing or not a file")
return a_file
def _require_dir_exists(a_dir: Path) -> Path:
if not a_dir.is_dir():
raise ValueError(f"{a_dir} missing or not a dir")
return a_dir
def _fonts_xml(android_dir: Path) -> Path:
return _require_exists(android_dir / "frameworks" / "base" / "data" / "fonts" / "fonts.xml")
def _fonts_mk(android_dir: Path) -> Path:
return _require_exists(android_dir / "external" / "noto-fonts" / "fonts.mk")
def _font_dir(android_dir: Path) -> Path:
return _require_dir_exists(android_dir / "external" / "noto-fonts" / "other")
def _repo_root() -> Path:
root = (Path(__file__).parent.parent).absolute()
if not (root / "LICENSE").is_file():
raise IOError(f"{root} does not contain LICENSE")
return root
def noto_4_android_path() -> Path:
xml_file = _repo_root() / "android_connection" / "noto-fonts-4-android.xml"
if not xml_file.is_file():
raise IOError(f"No file {xml_file}")
return xml_file
def font_file(font_el) -> str:
return ("".join(font_el.itertext())).strip()
def font_path(font_el) -> Path:
name = font_file(font_el)
path = font_el.attrib["path"]
return _require_exists(_repo_root() / path / name)
def _validate_android_path(android_dir: Path):
assert android_dir.is_dir(), f"{android_dir} should be a directory"
# just to trigger existance validation
_fonts_xml(android_dir)
_fonts_mk(android_dir)
_font_dir(android_dir)
def main(_):
if not FLAGS.android_root:
raise ValueError("Must provide --android_root")
android_dir = Path(FLAGS.android_root)
_validate_android_path(android_dir)
# gather fonts that should be copied to Android
noto_for_android = etree.parse(str(noto_4_android_path()))
new_paths = {}
for font_el in noto_for_android.xpath("//font[@path]"):
path = font_path(font_el)
if new_paths.get(path.name, path) != path:
raise IOError(f"Multiple paths for {path.name}")
new_paths[path.name] = path
old_paths = {p.name: p for p in _font_dir(android_dir).glob("Noto*.[ot]t[fc]")}
new_names = set(new_paths.keys())
old_names = set(old_paths.keys())
delta_sz = 0
deleted_files = old_names - new_names
print(f"{len(deleted_files)} DELETED")
for delete_me in sorted(deleted_files):
print(f" {delete_me}")
if not FLAGS.dry_run:
old_paths[delete_me].unlink()
del delete_me
del deleted_files
print()
added_files = new_names - old_names
print(f"{len(added_files)} ADDED")
for add_me in sorted(added_files):
dest = _font_dir(android_dir) / add_me
print(f" {add_me}")
if not FLAGS.dry_run:
shutil.copy(new_paths[add_me], dest)
del add_me
del added_files
print()
updated_files = new_names & old_names
untouched = 0
print(f"{len(updated_files)} UPDATED")
for update_me in sorted(updated_files):
if filecmp.cmp(new_paths[update_me], old_paths[update_me], shallow=False):
untouched += 1
continue
dest = _font_dir(android_dir) / update_me
print(f" {update_me}")
if not FLAGS.dry_run:
shutil.copy(new_paths[update_me], dest)
del update_me
del updated_files
print()
print(f"{untouched} did not change")
print()
print(f"Done updating files, you should manually update {_fonts_xml(android_dir)}"
f" from {noto_4_android_path()}")
if __name__ == "__main__":
app.run(main)