Support empty resources and project Android services
Sync changed files to Google Drive / sync (push) Successful in 1m2s
Sync changed files to Google Drive / sync (push) Successful in 1m2s
This commit is contained in:
1 parent
c6b5725c35
commit
19ee837986
5 files changed
+77
-6
No files matched your search
+42
-1
@@ -1,11 +1,12 @@
|
||||
"""Generate isolated Android CGE targets. No KaM stubs or rewritten game loaders."""
|
||||
from __future__ import annotations
|
||||
import hashlib, os, xml.etree.ElementTree as ET
|
||||
import hashlib, os, re, shutil, xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from common import ROOT, ProbeError
|
||||
|
||||
UPSTREAM_DEFINES=['DBG_SKIP_SECURE_AUTH'] # Existing upstream switch; private multiplayer authentication is out of scope.
|
||||
COMPILER_OPTIONS=['-B','-CX-','-XX-','-k--no-undefined','-k--no-gc-sections']
|
||||
_ANDROID_SERVICE_NAME=re.compile(r'[A-Za-z][A-Za-z0-9_]*\Z')
|
||||
|
||||
_PROJECT_ATTRIBUTES={
|
||||
'name':'kam_mobile', 'caption':'KaM Remake Mobile', 'author':'KaM Mobile',
|
||||
@@ -60,6 +61,33 @@ def _permanent_manifest() -> tuple[ET.ElementTree, ET.Element]:
|
||||
raise ProbeError('Invalid permanent compiler options')
|
||||
return tree,root
|
||||
|
||||
def android_service_roots(root: Path) -> tuple[Path,...]:
|
||||
"""Return validated immediate project-owned Android service directories."""
|
||||
try:
|
||||
if not root.exists(): return ()
|
||||
if root.is_symlink() or not root.is_dir():
|
||||
raise ProbeError('Android services root must be a real directory: '+str(root))
|
||||
resolved_root=root.resolve()
|
||||
services=[]
|
||||
for service in sorted(root.iterdir(),key=lambda path:path.name):
|
||||
if service.is_symlink():
|
||||
raise ProbeError('Android service must not be a symlink: '+str(service))
|
||||
if not service.is_dir(): continue
|
||||
if not _ANDROID_SERVICE_NAME.fullmatch(service.name):
|
||||
raise ProbeError('Unsafe Android service name: '+repr(service.name))
|
||||
resolved_service=service.resolve()
|
||||
if not resolved_service.is_relative_to(resolved_root):
|
||||
raise ProbeError('Android service escapes its root: '+str(service))
|
||||
for path in service.rglob('*'):
|
||||
if path.is_symlink():
|
||||
raise ProbeError('Android service contains a symlink: '+str(path))
|
||||
services.append(service)
|
||||
return tuple(services)
|
||||
except ProbeError:
|
||||
raise
|
||||
except (OSError, ValueError, RuntimeError) as error:
|
||||
raise ProbeError(f'Cannot inspect Android services: {error}') from error
|
||||
|
||||
def materialize_application_project(project: Path, source_resolution: dict) -> dict:
|
||||
"""Create one fresh Castle project from the permanent manifest and RP01 paths."""
|
||||
if project.exists():raise ProbeError('Target directory must be fresh: '+str(project))
|
||||
@@ -78,6 +106,19 @@ def materialize_application_project(project: Path, source_resolution: dict) -> d
|
||||
for path in paths:ET.SubElement(slot,'path',value=_manifest_path(path,project,kind))
|
||||
ET.indent(tree)
|
||||
tree.write(project/'CastleEngineManifest.xml',encoding='utf-8',xml_declaration=True)
|
||||
source_services=ROOT/'app/android_services'
|
||||
services=android_service_roots(source_services)
|
||||
if services:
|
||||
destination_root=project/'android_services'
|
||||
destination_root.mkdir()
|
||||
for service in services:
|
||||
destination=destination_root/service.name
|
||||
if destination.exists() or destination.is_symlink():
|
||||
raise ProbeError('Android service destination already exists: '+str(destination))
|
||||
try:
|
||||
shutil.copytree(service,destination)
|
||||
except OSError as error:
|
||||
raise ProbeError(f'Cannot copy Android service {service.name}: {error}') from error
|
||||
version=_one_child(root,'version')
|
||||
return {'project_dir':project,'data_root':data_root,'name':root.get('name'),'caption':root.get('caption'),
|
||||
'package':root.get('qualified_name'),'version':version.get('value'),'version_code':int(version.get('code')),
|
||||
|
||||
Reference in new issue
Block a user