NikGapps 3.95__tar.gz → 3.96__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/config_versions.json +3 -2
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/overlay_control.py +15 -0
- {nikgapps-3.95 → nikgapps-3.96/NikGapps.egg-info}/PKG-INFO +1 -1
- {nikgapps-3.95/NikGapps.egg-info → nikgapps-3.96}/PKG-INFO +1 -1
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/cli.py +19 -1
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/pipeline.py +32 -48
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/upgrade.py +75 -22
- {nikgapps-3.95 → nikgapps-3.96}/setup.py +1 -1
- {nikgapps-3.95 → nikgapps-3.96}/tests_package_pipeline/test_consumer.py +11 -16
- {nikgapps-3.95 → nikgapps-3.96}/tests_package_pipeline/test_overlay_control.py +13 -1
- {nikgapps-3.95 → nikgapps-3.96}/tests_package_pipeline/test_pipeline.py +12 -7
- {nikgapps-3.95 → nikgapps-3.96}/tests_package_pipeline/test_upgrade.py +38 -1
- {nikgapps-3.95 → nikgapps-3.96}/LICENSE +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/MANIFEST.in +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/Build.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/NikGappsManager.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/NikGappsOverlays.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/PackageConstants.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/Release.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/build_config.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/cache.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/config/NikGappsConfig.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/config/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/config_upload.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/copy_repos.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/AppSet.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/Args.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/Assets.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/Config.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/ConfigObj.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/Package.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/addon.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/appsets.json +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/changelogs.yaml +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/customize.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/debloater.config +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/functions.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/gofile.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/header.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/installer.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/magisk-update-binary.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/module.prop +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/mount.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/mtg_mount.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/nikgapps.config +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/nikgapps_functions.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/packages.json +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/uninstaller.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/assets/unmount.sh +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/compression/CompOps.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/compression/Export.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/compression/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/git/TestGit.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/git/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/ApkMetaInfo.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/Bool.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/Library.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/Manifest.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/Overlay.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/Resources.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/String.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/StringArray.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/helper/overlay/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/main.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps/test.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps.egg-info/SOURCES.txt +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps.egg-info/dependency_links.txt +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps.egg-info/entry_points.txt +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps.egg-info/requires.txt +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/NikGapps.egg-info/top_level.txt +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/README.md +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/__main__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/apk.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/archive.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/compat.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/config.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/consumer.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/errors.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/gitlab.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/models.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/scanner.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_package_pipeline/util.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_registry/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_registry/__main__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_registry/cli.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/nikgapps_registry/service.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/setup.cfg +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/tests_package_pipeline/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/tests_registry/__init__.py +0 -0
- {nikgapps-3.95 → nikgapps-3.96}/tests_registry/test_registry.py +0 -0
|
@@ -12,8 +12,22 @@ from niklibrary.git.Git import Git
|
|
|
12
12
|
from NikGapps.helper.overlay.Overlay import Overlay
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
ANDROID_PLATFORM_VERSIONS = {
|
|
16
|
+
# niklibrary 0.28 predates Android 17. Keep the compatibility entry here
|
|
17
|
+
# until the same mapping is available in the shared library.
|
|
18
|
+
"17": {"sdk": "37", "code": "CinnamonBun"},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def register_android_platform(android_version):
|
|
23
|
+
version = str(android_version)
|
|
24
|
+
if version not in Statics.android_versions and version in ANDROID_PLATFORM_VERSIONS:
|
|
25
|
+
Statics.android_versions[version] = ANDROID_PLATFORM_VERSIONS[version]
|
|
26
|
+
|
|
27
|
+
|
|
15
28
|
def build_local_overlays(android_version, source_dir, output_dir):
|
|
16
29
|
"""Generate and compile overlays locally without cloning or pushing repos."""
|
|
30
|
+
register_android_platform(android_version)
|
|
17
31
|
source_dir = os.path.abspath(source_dir)
|
|
18
32
|
output_dir = os.path.abspath(output_dir)
|
|
19
33
|
os.makedirs(source_dir, exist_ok=True)
|
|
@@ -40,6 +54,7 @@ def overlay_control():
|
|
|
40
54
|
android_versions = args.get_android_versions()
|
|
41
55
|
|
|
42
56
|
for android_version in android_versions:
|
|
57
|
+
register_android_platform(android_version)
|
|
43
58
|
repo_name = Statics.get_overlay_source_repo(android_version)
|
|
44
59
|
repo_dir = Statics.get_overlay_source_directory(android_version)
|
|
45
60
|
branch = "main"
|
|
@@ -168,6 +168,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
168
168
|
upgrade.add_argument("--baseline-firmware", type=Path, required=True)
|
|
169
169
|
upgrade.add_argument("--target-firmware", type=Path, required=True)
|
|
170
170
|
upgrade.add_argument("--output", type=Path, required=True)
|
|
171
|
+
upgrade.add_argument("--carry-forward-missing", action="store_true",
|
|
172
|
+
help="copy the complete template first, replace everything available from the target image, and audit retained files")
|
|
173
|
+
upgrade.add_argument("--android-version", help="build overlays for this Android version after upgrading")
|
|
174
|
+
upgrade.add_argument("--overlay-source", type=Path, help="generated overlay source workspace")
|
|
175
|
+
upgrade.add_argument("--overlay-output", type=Path, help="compiled overlay APK output")
|
|
171
176
|
return parser
|
|
172
177
|
|
|
173
178
|
|
|
@@ -336,9 +341,22 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
336
341
|
if args.command == "reset-registry":
|
|
337
342
|
return _reset_registry(args)
|
|
338
343
|
if args.command == "upgrade":
|
|
344
|
+
overlay_values = (args.android_version, args.overlay_source, args.overlay_output)
|
|
345
|
+
if any(overlay_values) and not all(overlay_values):
|
|
346
|
+
raise PipelineError("--android-version, --overlay-source, and --overlay-output must be supplied together")
|
|
347
|
+
overlays = []
|
|
348
|
+
if all(overlay_values):
|
|
349
|
+
from NikGapps.overlay_control import build_local_overlays
|
|
350
|
+
overlays = build_local_overlays(args.android_version, args.overlay_source, args.overlay_output)
|
|
339
351
|
report = StableTreeUpgrader().upgrade(
|
|
340
|
-
args.template, args.baseline_firmware, args.target_firmware, args.output
|
|
352
|
+
args.template, args.baseline_firmware, args.target_firmware, args.output,
|
|
353
|
+
carry_forward_missing=args.carry_forward_missing,
|
|
341
354
|
)
|
|
355
|
+
if overlays:
|
|
356
|
+
report.built_overlays = [str(Path(path).resolve().relative_to(args.overlay_output.resolve())).replace("\\", "/")
|
|
357
|
+
for path in overlays]
|
|
358
|
+
(args.output / "upgrade-report.json").write_text(
|
|
359
|
+
json.dumps(report.as_dict(), indent=2) + "\n", encoding="utf-8")
|
|
342
360
|
print(json.dumps(report.as_dict(), indent=2))
|
|
343
361
|
return 0
|
|
344
362
|
return _migrate(args)
|
|
@@ -377,13 +377,12 @@ class MigrationPipeline:
|
|
|
377
377
|
"with its required support files"
|
|
378
378
|
)
|
|
379
379
|
gms.dependencies = [
|
|
380
|
-
{"id": "gms_core_support_common"},
|
|
381
380
|
{
|
|
382
|
-
"id": "
|
|
381
|
+
"id": "gms_core_extra_files",
|
|
383
382
|
"when": {"appSet": "core"},
|
|
384
383
|
},
|
|
385
384
|
{
|
|
386
|
-
"id": "
|
|
385
|
+
"id": "gms_core_extra_files_go",
|
|
387
386
|
"when": {"appSet": "core_go"},
|
|
388
387
|
},
|
|
389
388
|
]
|
|
@@ -433,40 +432,28 @@ class MigrationPipeline:
|
|
|
433
432
|
normal_source = sources["Core/ExtraFiles"]
|
|
434
433
|
go_source = sources["CoreGo/ExtraFilesGo"]
|
|
435
434
|
scanner = LegacyRepositoryScanner()
|
|
436
|
-
normal = {item.path: item for item in scanner.payload(normal_source)}
|
|
437
|
-
go = {item.path: item for item in scanner.payload(go_source)}
|
|
438
|
-
common_paths = {
|
|
439
|
-
path for path in normal.keys() & go.keys()
|
|
440
|
-
if normal[path].sha256 == go[path].sha256
|
|
441
|
-
}
|
|
442
435
|
groups = [
|
|
443
436
|
(
|
|
444
|
-
"
|
|
445
|
-
"
|
|
446
|
-
|
|
447
|
-
["Core/ExtraFiles", "CoreGo/ExtraFilesGo"],
|
|
448
|
-
["Core", "CoreGo"],
|
|
449
|
-
),
|
|
450
|
-
(
|
|
451
|
-
"gms_core_support_standard",
|
|
452
|
-
"GmsCore standard support files",
|
|
453
|
-
[normal[path] for path in sorted(normal.keys() - common_paths)],
|
|
437
|
+
"gms_core_extra_files",
|
|
438
|
+
"ExtraFiles",
|
|
439
|
+
scanner.payload(normal_source),
|
|
454
440
|
["Core/ExtraFiles"],
|
|
455
441
|
["Core"],
|
|
442
|
+
normal_source,
|
|
456
443
|
),
|
|
457
444
|
(
|
|
458
|
-
"
|
|
459
|
-
"
|
|
460
|
-
|
|
445
|
+
"gms_core_extra_files_go",
|
|
446
|
+
"ExtraFilesGo",
|
|
447
|
+
scanner.payload(go_source),
|
|
461
448
|
["CoreGo/ExtraFilesGo"],
|
|
462
449
|
["CoreGo"],
|
|
450
|
+
go_source,
|
|
463
451
|
),
|
|
464
452
|
]
|
|
465
453
|
result: list[BuiltPackage] = []
|
|
466
|
-
for package_id, name, files, source_names, appset_names in groups:
|
|
454
|
+
for package_id, name, files, source_names, appset_names, support_source in groups:
|
|
467
455
|
if not files:
|
|
468
456
|
continue
|
|
469
|
-
support_source = normal_source if "go" not in package_id else go_source
|
|
470
457
|
payload_digest = content_digest((item.path, item.sha256) for item in files)
|
|
471
458
|
manifest = _manifest(package_id, support_source, files, None, None, [],
|
|
472
459
|
payload_digest, config)
|
|
@@ -588,32 +575,29 @@ class MigrationPipeline:
|
|
|
588
575
|
}
|
|
589
576
|
except (OSError, json.JSONDecodeError) as exc:
|
|
590
577
|
raise PipelineError(f"Cannot merge existing AppSets {appsets_path}: {exc}") from exc
|
|
591
|
-
generated_appsets = [
|
|
592
|
-
|
|
578
|
+
generated_appsets = []
|
|
579
|
+
for name, package_ids in sorted(appsets.items()):
|
|
580
|
+
selected = list(dict.fromkeys(package_ids))
|
|
581
|
+
resolved = MigrationPipeline._resolved_packages(name, selected, packages)
|
|
582
|
+
legacy_names = {}
|
|
583
|
+
for package_id in resolved:
|
|
584
|
+
legacy_names[package_id] = next(
|
|
585
|
+
(
|
|
586
|
+
membership.split("/", 1)[1]
|
|
587
|
+
for package in packages
|
|
588
|
+
if package.package_id == package_id
|
|
589
|
+
for membership in package.source_names
|
|
590
|
+
if membership.split("/", 1)[0] == name
|
|
591
|
+
),
|
|
592
|
+
package_id,
|
|
593
|
+
)
|
|
594
|
+
generated_appsets.append({
|
|
593
595
|
"id": stable_id(name),
|
|
594
596
|
"name": name,
|
|
595
|
-
"packages":
|
|
596
|
-
"resolvedPackages":
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
packages,
|
|
600
|
-
),
|
|
601
|
-
"legacyPackageNames": {
|
|
602
|
-
package_id: next(
|
|
603
|
-
(
|
|
604
|
-
membership.split("/", 1)[1]
|
|
605
|
-
for package in packages
|
|
606
|
-
if package.package_id == package_id
|
|
607
|
-
for membership in package.source_names
|
|
608
|
-
if membership.split("/", 1)[0] == name
|
|
609
|
-
),
|
|
610
|
-
package_id,
|
|
611
|
-
)
|
|
612
|
-
for package_id in dict.fromkeys(package_ids)
|
|
613
|
-
},
|
|
614
|
-
}
|
|
615
|
-
for name, package_ids in sorted(appsets.items())
|
|
616
|
-
]
|
|
597
|
+
"packages": selected,
|
|
598
|
+
"resolvedPackages": resolved,
|
|
599
|
+
"legacyPackageNames": legacy_names,
|
|
600
|
+
})
|
|
617
601
|
existing_appsets.update({item["id"]: item for item in generated_appsets})
|
|
618
602
|
appsets_path.write_bytes(json_data({
|
|
619
603
|
"schemaVersion": 1,
|
|
@@ -9,11 +9,24 @@ from typing import Any
|
|
|
9
9
|
from .errors import PipelineError
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
def _is_profile(path: Path) -> bool:
|
|
13
|
+
return path.suffix.casefold() == ".prof"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _ignore_profiles(_directory: str, names: list[str]) -> set[str]:
|
|
17
|
+
return {name for name in names if Path(name).suffix.casefold() == ".prof"}
|
|
18
|
+
|
|
19
|
+
|
|
12
20
|
@dataclass
|
|
13
21
|
class UpgradeReport:
|
|
14
22
|
upgraded_packages: list[str] = field(default_factory=list)
|
|
15
23
|
file_only_packages: list[str] = field(default_factory=list)
|
|
16
24
|
unavailable_packages: list[str] = field(default_factory=list)
|
|
25
|
+
carried_forward_packages: list[str] = field(default_factory=list)
|
|
26
|
+
updated_dependencies: list[str] = field(default_factory=list)
|
|
27
|
+
carried_forward_files: list[str] = field(default_factory=list)
|
|
28
|
+
ambiguous_dependencies: list[str] = field(default_factory=list)
|
|
29
|
+
built_overlays: list[str] = field(default_factory=list)
|
|
17
30
|
copied_files: int = 0
|
|
18
31
|
|
|
19
32
|
def as_dict(self) -> dict[str, Any]:
|
|
@@ -22,6 +35,11 @@ class UpgradeReport:
|
|
|
22
35
|
"upgradedPackages": sorted(self.upgraded_packages),
|
|
23
36
|
"fileOnlyPackages": sorted(self.file_only_packages),
|
|
24
37
|
"unavailablePackages": sorted(self.unavailable_packages),
|
|
38
|
+
"carriedForwardPackages": sorted(self.carried_forward_packages),
|
|
39
|
+
"updatedDependencies": sorted(self.updated_dependencies),
|
|
40
|
+
"carriedForwardFiles": sorted(self.carried_forward_files),
|
|
41
|
+
"ambiguousDependencies": sorted(self.ambiguous_dependencies),
|
|
42
|
+
"builtOverlays": sorted(self.built_overlays),
|
|
25
43
|
"copiedFiles": self.copied_files,
|
|
26
44
|
}
|
|
27
45
|
|
|
@@ -95,7 +113,8 @@ def _copy_firmware_directory(
|
|
|
95
113
|
source_directory = source_apk.parent
|
|
96
114
|
count = 0
|
|
97
115
|
for source in sorted(source_directory.rglob("*")):
|
|
98
|
-
if not source.is_file() or
|
|
116
|
+
if (not source.is_file() or _is_profile(source)
|
|
117
|
+
or any(part.endswith("_extracted") for part in source.parts)):
|
|
99
118
|
continue
|
|
100
119
|
source_location = Path(location).parent / source.relative_to(source_directory)
|
|
101
120
|
destination = package_output / encode_builder_path(source_location.as_posix())
|
|
@@ -114,6 +133,8 @@ class StableTreeUpgrader:
|
|
|
114
133
|
baseline_firmware: Path,
|
|
115
134
|
target_firmware: Path,
|
|
116
135
|
output: Path,
|
|
136
|
+
*,
|
|
137
|
+
carry_forward_missing: bool = False,
|
|
117
138
|
) -> UpgradeReport:
|
|
118
139
|
template_root = template_root.resolve()
|
|
119
140
|
baseline_firmware = baseline_firmware.resolve()
|
|
@@ -128,6 +149,18 @@ class StableTreeUpgrader:
|
|
|
128
149
|
|
|
129
150
|
baseline = _load_inventory(baseline_firmware)
|
|
130
151
|
target = _load_inventory(target_firmware)
|
|
152
|
+
target_files: dict[str, list[Path]] = {}
|
|
153
|
+
for candidate in sorted(target_firmware.rglob("*")):
|
|
154
|
+
if not candidate.is_file() or candidate.name in {"mustang.json", "all_files.txt"}:
|
|
155
|
+
continue
|
|
156
|
+
if any(part.endswith("_extracted") or part == ".git" for part in candidate.parts):
|
|
157
|
+
continue
|
|
158
|
+
relative = candidate.relative_to(target_firmware).as_posix()
|
|
159
|
+
try:
|
|
160
|
+
builder_path = encode_builder_path(relative).as_posix()
|
|
161
|
+
except PipelineError:
|
|
162
|
+
continue
|
|
163
|
+
target_files.setdefault(builder_path, []).append(candidate)
|
|
131
164
|
report = UpgradeReport()
|
|
132
165
|
output.mkdir(parents=True)
|
|
133
166
|
for metadata_name in (".gitattributes", "README.md"):
|
|
@@ -141,10 +174,18 @@ class StableTreeUpgrader:
|
|
|
141
174
|
destination = output / appset.name / package.name
|
|
142
175
|
# Preserve the complete AppSet/package skeleton even when a
|
|
143
176
|
# package is not shipped by the target firmware image.
|
|
144
|
-
|
|
177
|
+
if carry_forward_missing:
|
|
178
|
+
shutil.copytree(package, destination, ignore=_ignore_profiles)
|
|
179
|
+
else:
|
|
180
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
145
181
|
template_apks = sorted(package.rglob("*.apk"))
|
|
182
|
+
template_dependencies = sorted(
|
|
183
|
+
path for path in package.rglob("*")
|
|
184
|
+
if path.is_file() and path.suffix.casefold() not in {".apk", ".prof"}
|
|
185
|
+
)
|
|
146
186
|
copied = 0
|
|
147
187
|
seen_targets: set[str] = set()
|
|
188
|
+
replaced_apk_parents: set[Path] = set()
|
|
148
189
|
for template_apk in template_apks:
|
|
149
190
|
match = _record_for_template(template_apk, package, baseline)
|
|
150
191
|
if not match:
|
|
@@ -157,36 +198,48 @@ class StableTreeUpgrader:
|
|
|
157
198
|
if location in seen_targets:
|
|
158
199
|
continue
|
|
159
200
|
seen_targets.add(location)
|
|
201
|
+
if carry_forward_missing:
|
|
202
|
+
old_parent = destination / template_apk.parent.relative_to(package)
|
|
203
|
+
if old_parent not in replaced_apk_parents:
|
|
204
|
+
shutil.rmtree(old_parent)
|
|
205
|
+
replaced_apk_parents.add(old_parent)
|
|
160
206
|
copied += _copy_firmware_directory(target_firmware, target_record, destination)
|
|
161
207
|
|
|
208
|
+
dependency_copied = 0
|
|
209
|
+
for template_file in template_dependencies:
|
|
210
|
+
relative = template_file.relative_to(package)
|
|
211
|
+
builder_path = relative.as_posix()
|
|
212
|
+
matches = target_files.get(builder_path, [])
|
|
213
|
+
audit_path = f"{membership}/{builder_path}"
|
|
214
|
+
if len(matches) == 1:
|
|
215
|
+
destination_file = destination / relative
|
|
216
|
+
destination_file.parent.mkdir(parents=True, exist_ok=True)
|
|
217
|
+
shutil.copy2(matches[0], destination_file)
|
|
218
|
+
dependency_copied += 1
|
|
219
|
+
report.copied_files += 1
|
|
220
|
+
report.updated_dependencies.append(audit_path)
|
|
221
|
+
elif len(matches) > 1:
|
|
222
|
+
report.ambiguous_dependencies.append(audit_path)
|
|
223
|
+
if carry_forward_missing and destination.joinpath(relative).is_file():
|
|
224
|
+
report.carried_forward_files.append(audit_path)
|
|
225
|
+
elif carry_forward_missing and destination.joinpath(relative).is_file():
|
|
226
|
+
report.carried_forward_files.append(audit_path)
|
|
227
|
+
|
|
162
228
|
if copied:
|
|
163
229
|
report.upgraded_packages.append(membership)
|
|
164
230
|
report.copied_files += copied
|
|
231
|
+
if carry_forward_missing and any(
|
|
232
|
+
destination.joinpath(apk.relative_to(package)).is_file() for apk in template_apks
|
|
233
|
+
):
|
|
234
|
+
report.carried_forward_packages.append(membership)
|
|
165
235
|
continue
|
|
166
236
|
|
|
167
|
-
|
|
168
|
-
# present in Android 17. Nothing is ever copied from Android 16.
|
|
169
|
-
file_only_copied = 0
|
|
170
|
-
for template_file in sorted(package.rglob("*")):
|
|
171
|
-
if not template_file.is_file() or template_file.suffix == ".apk":
|
|
172
|
-
continue
|
|
173
|
-
suffix = decode_builder_path(template_file.relative_to(package))
|
|
174
|
-
matches = [
|
|
175
|
-
candidate for candidate in target_firmware.rglob(template_file.name)
|
|
176
|
-
if candidate.is_file()
|
|
177
|
-
and candidate.as_posix().endswith("/" + suffix)
|
|
178
|
-
and "_extracted" not in candidate.as_posix()
|
|
179
|
-
]
|
|
180
|
-
if len(matches) == 1:
|
|
181
|
-
destination_file = destination / template_file.relative_to(package)
|
|
182
|
-
destination_file.parent.mkdir(parents=True, exist_ok=True)
|
|
183
|
-
shutil.copy2(matches[0], destination_file)
|
|
184
|
-
report.copied_files += 1
|
|
185
|
-
file_only_copied += 1
|
|
186
|
-
if file_only_copied:
|
|
237
|
+
if dependency_copied:
|
|
187
238
|
report.file_only_packages.append(membership)
|
|
188
239
|
else:
|
|
189
240
|
report.unavailable_packages.append(membership)
|
|
241
|
+
if carry_forward_missing and any(destination.rglob("*")):
|
|
242
|
+
report.carried_forward_packages.append(membership)
|
|
190
243
|
|
|
191
244
|
(output / "upgrade-report.json").write_text(
|
|
192
245
|
json.dumps(report.as_dict(), indent=2) + "\n", encoding="utf-8"
|
|
@@ -57,21 +57,17 @@ class ConsumerTests(unittest.TestCase):
|
|
|
57
57
|
"gms_core": artifact(
|
|
58
58
|
root, "gms", "priv-app/Gms/Gms.apk", b"apk"
|
|
59
59
|
),
|
|
60
|
-
"
|
|
61
|
-
root, "
|
|
60
|
+
"gms_core_extra_files": artifact(
|
|
61
|
+
root, "extra", "etc/permissions/common.xml", b"common"
|
|
62
62
|
),
|
|
63
|
-
"
|
|
64
|
-
root, "standard", "etc/sysconfig/variant.xml", b"standard"
|
|
65
|
-
),
|
|
66
|
-
"gms_core_support_go": artifact(
|
|
63
|
+
"gms_core_extra_files_go": artifact(
|
|
67
64
|
root, "go", "etc/sysconfig/go.xml", b"go"
|
|
68
65
|
),
|
|
69
66
|
}
|
|
70
67
|
memberships = {
|
|
71
68
|
"gms_core": ["Core/GmsCore", "CoreGo/GmsCore"],
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"gms_core_support_go": ["CoreGo/ExtraFilesGo"],
|
|
69
|
+
"gms_core_extra_files": ["Core/ExtraFiles"],
|
|
70
|
+
"gms_core_extra_files_go": ["CoreGo/ExtraFilesGo"],
|
|
75
71
|
}
|
|
76
72
|
packages = []
|
|
77
73
|
for package_id, artifact_data in artifacts.items():
|
|
@@ -83,7 +79,7 @@ class ConsumerTests(unittest.TestCase):
|
|
|
83
79
|
"versions": {
|
|
84
80
|
key: {
|
|
85
81
|
"android": {"minApi": 29, "maxApi": None},
|
|
86
|
-
"architectures": [] if "
|
|
82
|
+
"architectures": [] if "extra_files" in package_id else ["arm64-v8a"],
|
|
87
83
|
"artifact": artifact_data,
|
|
88
84
|
}
|
|
89
85
|
},
|
|
@@ -98,10 +94,12 @@ class ConsumerTests(unittest.TestCase):
|
|
|
98
94
|
"packages": ["gms_core"],
|
|
99
95
|
"resolvedPackages": [
|
|
100
96
|
"gms_core",
|
|
101
|
-
"
|
|
102
|
-
"gms_core_support_standard",
|
|
97
|
+
"gms_core_extra_files",
|
|
103
98
|
],
|
|
104
|
-
"legacyPackageNames": {
|
|
99
|
+
"legacyPackageNames": {
|
|
100
|
+
"gms_core": "GmsCore",
|
|
101
|
+
"gms_core_extra_files": "ExtraFiles",
|
|
102
|
+
},
|
|
105
103
|
}]
|
|
106
104
|
}), encoding="utf-8")
|
|
107
105
|
requested = [SimpleNamespace(
|
|
@@ -120,9 +118,6 @@ class ConsumerTests(unittest.TestCase):
|
|
|
120
118
|
self.assertTrue(
|
|
121
119
|
(source / "Core" / "ExtraFiles" / "___etc___permissions" / "common.xml").is_file()
|
|
122
120
|
)
|
|
123
|
-
self.assertTrue(
|
|
124
|
-
(source / "Core" / "ExtraFiles" / "___etc___sysconfig" / "variant.xml").is_file()
|
|
125
|
-
)
|
|
126
121
|
self.assertFalse((source / "CoreGo").exists())
|
|
127
122
|
|
|
128
123
|
def test_checksum_mismatch_is_rejected(self) -> None:
|
|
@@ -10,7 +10,8 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "niklibrary"))
|
|
|
10
10
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "nikassets"))
|
|
11
11
|
|
|
12
12
|
try:
|
|
13
|
-
from NikGapps.overlay_control import build_local_overlays
|
|
13
|
+
from NikGapps.overlay_control import build_local_overlays, register_android_platform
|
|
14
|
+
from niklibrary.helper.Statics import Statics
|
|
14
15
|
except ModuleNotFoundError:
|
|
15
16
|
build_local_overlays = None
|
|
16
17
|
|
|
@@ -26,6 +27,17 @@ class FakeOverlay:
|
|
|
26
27
|
|
|
27
28
|
@unittest.skipIf(build_local_overlays is None, "optional NikGapps build dependencies unavailable")
|
|
28
29
|
class OverlayControlTests(unittest.TestCase):
|
|
30
|
+
def test_android_17_platform_compatibility(self) -> None:
|
|
31
|
+
original = Statics.android_versions.pop("17", None)
|
|
32
|
+
try:
|
|
33
|
+
register_android_platform("17")
|
|
34
|
+
self.assertEqual(Statics.get_android_sdk("17"), "37")
|
|
35
|
+
self.assertEqual(Statics.get_android_code("17"), "CinnamonBun")
|
|
36
|
+
finally:
|
|
37
|
+
Statics.android_versions.pop("17", None)
|
|
38
|
+
if original is not None:
|
|
39
|
+
Statics.android_versions["17"] = original
|
|
40
|
+
|
|
29
41
|
def test_android_17_local_overlay_output(self) -> None:
|
|
30
42
|
with tempfile.TemporaryDirectory() as temporary:
|
|
31
43
|
root = Path(temporary)
|
|
@@ -293,9 +293,8 @@ class MigrationTests(unittest.TestCase):
|
|
|
293
293
|
"example",
|
|
294
294
|
"shared",
|
|
295
295
|
"gms_core",
|
|
296
|
-
"
|
|
297
|
-
"
|
|
298
|
-
"gms_core_support_go",
|
|
296
|
+
"gms_core_extra_files",
|
|
297
|
+
"gms_core_extra_files_go",
|
|
299
298
|
},
|
|
300
299
|
)
|
|
301
300
|
shared = next(item for item in packages if item.package_id == "shared")
|
|
@@ -306,10 +305,16 @@ class MigrationTests(unittest.TestCase):
|
|
|
306
305
|
)
|
|
307
306
|
support = next(
|
|
308
307
|
item for item in packages
|
|
309
|
-
if item.package_id == "
|
|
308
|
+
if item.package_id == "gms_core_extra_files"
|
|
310
309
|
)
|
|
311
310
|
self.assertIsNone(support.primary_apk)
|
|
312
311
|
self.assertTrue(support.internal)
|
|
312
|
+
with zipfile.ZipFile(support.artifact_path) as support_archive:
|
|
313
|
+
support_installer = support_archive.read("installer.sh").decode()
|
|
314
|
+
support_uninstaller = support_archive.read("uninstaller.sh").decode()
|
|
315
|
+
self.assertIn("com.google.android.maps.xml", support_installer)
|
|
316
|
+
self.assertIn("uninstall_package() {", support_uninstaller)
|
|
317
|
+
self.assertIn("___etc___permissions/common.xml", support_uninstaller)
|
|
313
318
|
self.assertRegex(
|
|
314
319
|
support.version_key,
|
|
315
320
|
r"^content-[0-9a-f]{12}-arm64-v8a$",
|
|
@@ -344,9 +349,9 @@ class MigrationTests(unittest.TestCase):
|
|
|
344
349
|
appsets = json.loads((output / "metadata" / "appsets.json").read_text())
|
|
345
350
|
core_go = next(item for item in appsets["appSets"] if item["name"] == "CoreGo")
|
|
346
351
|
self.assertEqual(core_go["packages"], ["gms_core", "shared"])
|
|
347
|
-
self.assertIn("
|
|
348
|
-
self.
|
|
349
|
-
self.
|
|
352
|
+
self.assertIn("gms_core_extra_files_go", core_go["resolvedPackages"])
|
|
353
|
+
self.assertNotIn("gms_core_extra_files", core_go["resolvedPackages"])
|
|
354
|
+
self.assertEqual(core_go["legacyPackageNames"]["gms_core_extra_files_go"], "ExtraFilesGo")
|
|
350
355
|
compatible = Path(temporary) / "compatible"
|
|
351
356
|
LegacyCompatibilityExporter().export(packages, compatible)
|
|
352
357
|
self.assertTrue(
|
|
@@ -43,7 +43,7 @@ class StableTreeUpgradeTests(unittest.TestCase):
|
|
|
43
43
|
|
|
44
44
|
upgraded = output / "Set" / "App" / "___priv-app___AppNew_17"
|
|
45
45
|
self.assertEqual((upgraded / "AppNew_17.apk").read_bytes(), b"new")
|
|
46
|
-
self.
|
|
46
|
+
self.assertFalse((upgraded / "AppNew_17.apk.prof").exists())
|
|
47
47
|
self.assertEqual(report.upgraded_packages, ["Set/App"])
|
|
48
48
|
self.assertFalse((output / "Set" / "App" / "___priv-app___AppOld").exists())
|
|
49
49
|
|
|
@@ -59,6 +59,43 @@ class StableTreeUpgradeTests(unittest.TestCase):
|
|
|
59
59
|
root / "template", root / "old", root / "new", root / "output"
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
+
def test_complete_upgrade_replaces_dependencies_and_audits_carry_forward(self) -> None:
|
|
63
|
+
with tempfile.TemporaryDirectory() as temporary:
|
|
64
|
+
root = Path(temporary)
|
|
65
|
+
template = root / "16_stable"
|
|
66
|
+
old = root / "16_mustang"
|
|
67
|
+
new = root / "17_mustang"
|
|
68
|
+
output = root / "17_stable"
|
|
69
|
+
old_location = "product/priv-app/AppOld/AppOld.apk"
|
|
70
|
+
new_location = "product/priv-app/AppNew/AppNew.apk"
|
|
71
|
+
self.inventory(old, "com.example", old_location)
|
|
72
|
+
self.inventory(new, "com.example", new_location)
|
|
73
|
+
(old / old_location).parent.mkdir(parents=True)
|
|
74
|
+
(old / old_location).write_bytes(b"old")
|
|
75
|
+
(new / new_location).parent.mkdir(parents=True)
|
|
76
|
+
(new / new_location).write_bytes(b"new")
|
|
77
|
+
(new / "product/etc/permissions/updated.xml").parent.mkdir(parents=True)
|
|
78
|
+
(new / "product/etc/permissions/updated.xml").write_bytes(b"17")
|
|
79
|
+
package = template / "Set" / "App"
|
|
80
|
+
(package / "___priv-app___AppOld").mkdir(parents=True)
|
|
81
|
+
(package / "___priv-app___AppOld/AppOld.apk").write_bytes(b"template")
|
|
82
|
+
(package / "___etc___permissions").mkdir(parents=True)
|
|
83
|
+
(package / "___etc___permissions/updated.xml").write_bytes(b"16")
|
|
84
|
+
(package / "___etc___permissions/retained.xml").write_bytes(b"retain")
|
|
85
|
+
(package / "___priv-app___AppOld/AppOld.apk.prof").write_bytes(b"old profile")
|
|
86
|
+
|
|
87
|
+
report = StableTreeUpgrader().upgrade(
|
|
88
|
+
template, old, new, output, carry_forward_missing=True)
|
|
89
|
+
|
|
90
|
+
upgraded = output / "Set/App"
|
|
91
|
+
self.assertFalse((upgraded / "___priv-app___AppOld").exists())
|
|
92
|
+
self.assertEqual((upgraded / "___priv-app___AppNew/AppNew.apk").read_bytes(), b"new")
|
|
93
|
+
self.assertEqual((upgraded / "___etc___permissions/updated.xml").read_bytes(), b"17")
|
|
94
|
+
self.assertEqual((upgraded / "___etc___permissions/retained.xml").read_bytes(), b"retain")
|
|
95
|
+
self.assertFalse(any(upgraded.rglob("*.prof")))
|
|
96
|
+
self.assertIn("Set/App/___etc___permissions/updated.xml", report.updated_dependencies)
|
|
97
|
+
self.assertIn("Set/App/___etc___permissions/retained.xml", report.carried_forward_files)
|
|
98
|
+
|
|
62
99
|
|
|
63
100
|
if __name__ == "__main__":
|
|
64
101
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|