Document resources staging groups and finalization
Includes instructions on how to expose new public resource IDs and how to "remove" unused resource IDs before finalization. Temporarily restricts OWNERS to ensure T remains stable until a long term static analysis solution is found. Fixes the script for finalization to handle split files and seed the next release's staging-public-group blocks. Bug: 222537368 Test: manual, checked build before and after mock finalization Change-Id: I901a80e487f5eaab9689f469196648535857e0e1
This commit is contained in:
141
tools/aapt2/tools/finalize_res.py
Executable file
141
tools/aapt2/tools/finalize_res.py
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2022 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Finalize resource values in <staging-public-group> tags
|
||||
and convert those to <staging-public-group-final>
|
||||
|
||||
Usage: $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \
|
||||
$ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-staging.xml \
|
||||
$ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-final.xml
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
resTypes = ["attr", "id", "style", "string", "dimen", "color", "array", "drawable", "layout",
|
||||
"anim", "animator", "interpolator", "mipmap", "integer", "transition", "raw", "bool",
|
||||
"fraction"]
|
||||
|
||||
_type_ids = {}
|
||||
_type = ""
|
||||
|
||||
_lowest_staging_first_id = 0x01FFFFFF
|
||||
|
||||
"""
|
||||
Created finalized <public> declarations for staging resources, ignoring them if they've been
|
||||
prefixed with removed_. The IDs are assigned without holes starting from the last ID for that
|
||||
type currently finalized in public-final.xml.
|
||||
"""
|
||||
def finalize_item(raw):
|
||||
name = raw.group(1)
|
||||
if re.match(r'_*removed.+', name):
|
||||
return ""
|
||||
id = _type_ids[_type]
|
||||
_type_ids[_type] += 1
|
||||
return ' <public type="%s" name="%s" id="%s" />\n' % (_type, name, '0x{0:0{1}x}'.format(id, 8))
|
||||
|
||||
|
||||
"""
|
||||
Finalizes staging-public-groups if they have any entries in them. Also keeps track of the
|
||||
lowest first-id of the non-empty groups so that the next release's staging-public-groups can
|
||||
be assigned the next down shifted first-id.
|
||||
"""
|
||||
def finalize_group(raw):
|
||||
global _type, _lowest_staging_first_id
|
||||
_type = raw.group(1)
|
||||
id = int(raw.group(2), 16)
|
||||
_type_ids[_type] = _type_ids.get(_type, id)
|
||||
(res, count) = re.subn(' {0,4}<public name="(.+?)" */>\n', finalize_item, raw.group(3))
|
||||
if count > 0:
|
||||
res = raw.group(0).replace("staging-public-group",
|
||||
"staging-public-group-final") + '\n' + res
|
||||
_lowest_staging_first_id = min(id, _lowest_staging_first_id)
|
||||
return res
|
||||
|
||||
"""
|
||||
Collects the max ID for each resType so that the new IDs can be assigned afterwards
|
||||
"""
|
||||
def collect_ids(raw):
|
||||
for m in re.finditer(r'<public type="(.+?)" name=".+?" id="(.+?)" />', raw):
|
||||
type = m.group(1)
|
||||
id = int(m.group(2), 16)
|
||||
_type_ids[type] = max(id + 1, _type_ids.get(type, 0))
|
||||
|
||||
|
||||
with open(sys.argv[1], "r+") as stagingFile:
|
||||
with open(sys.argv[2], "r+") as finalFile:
|
||||
existing = finalFile.read()
|
||||
# Cut out the closing resources tag so that it can be concatenated easily later
|
||||
existing = "\n".join(existing.rsplit("</resources>", 1))
|
||||
|
||||
# Collect the IDs from the existing already finalized resources
|
||||
collect_ids(existing)
|
||||
|
||||
staging = stagingFile.read()
|
||||
stagingSplit = staging.rsplit("<resources>")
|
||||
staging = stagingSplit[1]
|
||||
staging = re.sub(
|
||||
r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>',
|
||||
finalize_group, staging, flags=re.DOTALL)
|
||||
staging = re.sub(r' *\n', '\n', staging)
|
||||
staging = re.sub(r'\n{3,}', '\n\n', staging)
|
||||
|
||||
# First write the existing finalized declarations and then append the new stuff
|
||||
finalFile.seek(0)
|
||||
finalFile.write(existing.strip("\n"))
|
||||
finalFile.write("\n\n")
|
||||
finalFile.write(staging.strip("\n"))
|
||||
finalFile.write("\n")
|
||||
finalFile.truncate()
|
||||
|
||||
stagingFile.seek(0)
|
||||
# Include the documentation from public-staging.xml that was previously split out
|
||||
stagingFile.write(stagingSplit[0])
|
||||
# Write the next platform header
|
||||
stagingFile.write("<resources>\n\n")
|
||||
stagingFile.write(" <!-- ===============================================================\n")
|
||||
stagingFile.write(" Resources added in version NEXT of the platform\n\n")
|
||||
stagingFile.write(" NOTE: After this version of the platform is forked, changes cannot be made to the root\n")
|
||||
stagingFile.write(" branch's groups for that release. Only merge changes to the forked platform branch.\n")
|
||||
stagingFile.write(" =============================================================== -->\n")
|
||||
stagingFile.write(" <eat-comment/>\n\n")
|
||||
|
||||
# Seed the next release's staging-public-groups as empty declarations,
|
||||
# so its easy for another developer to expose a new public resource
|
||||
nextId = _lowest_staging_first_id - 0x00010000
|
||||
for resType in resTypes:
|
||||
stagingFile.write(' <staging-public-group type="%s" first-id="%s">\n'
|
||||
' </staging-public-group>\n\n' %
|
||||
(resType, '0x{0:0{1}x}'.format(nextId, 8)))
|
||||
nextId -= 0x00010000
|
||||
|
||||
# Close the resources tag and truncate, since the file will be shorter than the previous
|
||||
stagingFile.write("</resources>\n")
|
||||
stagingFile.truncate()
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2021 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Finalize resource values in <staging-public-group> tags
|
||||
|
||||
Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml
|
||||
"""
|
||||
|
||||
import re, sys, codecs
|
||||
|
||||
def finalize_item(raw):
|
||||
global _type, _id
|
||||
_id += 1
|
||||
return '<public type="%s" name="%s" id="%s" />' % (_type, raw.group(1), '0x{0:0{1}x}'.format(_id-1,8))
|
||||
|
||||
def finalize_group(raw):
|
||||
global _type, _id
|
||||
_type = raw.group(1)
|
||||
_id = int(raw.group(2), 16)
|
||||
return re.sub(r'<public name="(.+?)" */>', finalize_item, raw.group(3))
|
||||
|
||||
with open(sys.argv[1]) as f:
|
||||
raw = f.read()
|
||||
raw = re.sub(r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>', finalize_group, raw, flags=re.DOTALL)
|
||||
with open(sys.argv[2], "w") as f:
|
||||
f.write(raw)
|
||||
Reference in New Issue
Block a user