carriersettings-extractor: Implement argparse, extract files into separate folders
Co-Authored-By: Michael Bestas <mkbestas@gmail.com> Change-Id: If8d93d832bbd586ae0e06067a4e335aa5a0398c4
This commit is contained in:
committed by
Michael Bestas
parent
ae25298473
commit
e1499e0324
@@ -16,7 +16,7 @@ For a description of each APN and carrier setting, refer to the doc comments in
|
|||||||
Download a [Pixel factory image](https://developers.google.com/android/images) and extract the CarrierSettings protobuf files.
|
Download a [Pixel factory image](https://developers.google.com/android/images) and extract the CarrierSettings protobuf files.
|
||||||
Convert `CarrierSettings/*.pb` to `apns-full-conf.xml` and `vendor.xml`.
|
Convert `CarrierSettings/*.pb` to `apns-full-conf.xml` and `vendor.xml`.
|
||||||
|
|
||||||
./carriersettings_extractor.py CarrierSettings
|
./carriersettings_extractor.py -i CarrierSettings -a apns-conf.xml -v vendor.xml
|
||||||
|
|
||||||
## Protobuf definitions
|
## Protobuf definitions
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from itertools import product
|
from itertools import product
|
||||||
@@ -12,13 +13,48 @@ from carriersettings_pb2 import CarrierList, CarrierSettings, \
|
|||||||
MultiCarrierSettings
|
MultiCarrierSettings
|
||||||
from carrierId_pb2 import CarrierList as CarrierIdList
|
from carrierId_pb2 import CarrierList as CarrierIdList
|
||||||
|
|
||||||
pb_path = sys.argv[1]
|
|
||||||
|
|
||||||
carrier_id_list = CarrierIdList()
|
def indent(elem, level=0):
|
||||||
carrier_attribute_map = {}
|
"""Based on https://effbot.org/zone/element-lib.htm#prettyprint"""
|
||||||
with open('carrier_list.pb', 'rb') as pb:
|
i = "\n" + level * " "
|
||||||
|
if len(elem):
|
||||||
|
if not elem.text or not elem.text.strip():
|
||||||
|
elem.text = i + " "
|
||||||
|
if not elem.tail or not elem.tail.strip():
|
||||||
|
elem.tail = i
|
||||||
|
for elem in elem:
|
||||||
|
indent(elem, level + 1)
|
||||||
|
if not elem.tail or not elem.tail.strip():
|
||||||
|
elem.tail = i
|
||||||
|
else:
|
||||||
|
if level and (not elem.tail or not elem.tail.strip()):
|
||||||
|
elem.tail = i
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Convert the CarrierSettings protobuf files to XML format compatible with AOSP")
|
||||||
|
parser.add_argument('-i', '--input', help='CarrierSettings folder',
|
||||||
|
required=True)
|
||||||
|
parser.add_argument('-a', '--apns', help='apns-conf.xml Output folder',
|
||||||
|
required=True)
|
||||||
|
parser.add_argument('-v', '--vendor', help='vendor.xml Output folder',
|
||||||
|
required=True)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
input_folder = args.input
|
||||||
|
apns_folder = args.apns
|
||||||
|
vendor_folder = args.vendor
|
||||||
|
|
||||||
|
carrier_id_list = CarrierIdList()
|
||||||
|
carrier_attribute_map = {}
|
||||||
|
with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'carrier_list.pb'), 'rb') as pb:
|
||||||
carrier_id_list.ParseFromString(pb.read())
|
carrier_id_list.ParseFromString(pb.read())
|
||||||
for carrier_id_obj in carrier_id_list.carrier_id:
|
for carrier_id_obj in carrier_id_list.carrier_id:
|
||||||
for carrier_attribute in carrier_id_obj.carrier_attribute:
|
for carrier_attribute in carrier_id_obj.carrier_attribute:
|
||||||
for carrier_attributes in product(*(
|
for carrier_attributes in product(*(
|
||||||
(s.lower() for s in getattr(carrier_attribute, i) or [''])
|
(s.lower() for s in getattr(carrier_attribute, i) or [''])
|
||||||
@@ -31,9 +67,9 @@ for carrier_id_obj in carrier_id_list.carrier_id:
|
|||||||
carrier_attribute_map[carrier_attributes] = \
|
carrier_attribute_map[carrier_attributes] = \
|
||||||
carrier_id_obj.canonical_id
|
carrier_id_obj.canonical_id
|
||||||
|
|
||||||
carrier_list = CarrierList()
|
carrier_list = CarrierList()
|
||||||
all_settings = {}
|
all_settings = {}
|
||||||
for filename in glob(os.path.join(pb_path, '*.pb')):
|
for filename in glob(os.path.join(input_folder, '*.pb')):
|
||||||
with open(filename, 'rb') as pb:
|
with open(filename, 'rb') as pb:
|
||||||
if os.path.basename(filename) == 'carrier_list.pb':
|
if os.path.basename(filename) == 'carrier_list.pb':
|
||||||
carrier_list.ParseFromString(pb.read())
|
carrier_list.ParseFromString(pb.read())
|
||||||
@@ -49,21 +85,21 @@ for filename in glob(os.path.join(pb_path, '*.pb')):
|
|||||||
assert setting.canonicalName not in all_settings
|
assert setting.canonicalName not in all_settings
|
||||||
all_settings[setting.canonicalName] = setting
|
all_settings[setting.canonicalName] = setting
|
||||||
|
|
||||||
|
carrier_config_root = ET.Element('carrier_config_list')
|
||||||
|
|
||||||
# Unfortunately, python processors like xml and lxml, as well as command-line
|
# Unfortunately, python processors like xml and lxml, as well as command-line
|
||||||
# utilities like tidy, do not support the exact style used by AOSP for
|
# utilities like tidy, do not support the exact style used by AOSP for
|
||||||
# apns-full-conf.xml:
|
# apns-conf.xml:
|
||||||
#
|
#
|
||||||
# * indent: 2 spaces
|
# * indent: 2 spaces
|
||||||
# * attribute indent: 4 spaces
|
# * attribute indent: 4 spaces
|
||||||
# * blank lines between elements
|
# * blank lines between elements
|
||||||
# * attributes after first indented on separate lines
|
# * attributes after first indented on separate lines
|
||||||
# * closing tags of multi-line elements on separate, unindented lines
|
# * closing tags of multi-line elements on separate, unindented lines
|
||||||
#
|
#
|
||||||
# Therefore, we build the file without using an XML processor.
|
# Therefore, we build the file without using an XML processor.
|
||||||
|
|
||||||
|
class ApnElement:
|
||||||
class ApnElement:
|
|
||||||
def __init__(self, apn, carrier_id):
|
def __init__(self, apn, carrier_id):
|
||||||
self.apn = apn
|
self.apn = apn
|
||||||
self.carrier_id = carrier_id
|
self.carrier_id = carrier_id
|
||||||
@@ -153,31 +189,10 @@ class ApnElement:
|
|||||||
self.add_attribute('user_visible', 'userVisible')
|
self.add_attribute('user_visible', 'userVisible')
|
||||||
self.add_attribute('user_editable', 'userEditable')
|
self.add_attribute('user_editable', 'userEditable')
|
||||||
|
|
||||||
|
with open(os.path.join(apns_folder, 'apns-conf.xml'), 'w', encoding='utf-8') as f:
|
||||||
def indent(elem, level=0):
|
|
||||||
"""Based on https://effbot.org/zone/element-lib.htm#prettyprint"""
|
|
||||||
i = "\n" + level * " "
|
|
||||||
if len(elem):
|
|
||||||
if not elem.text or not elem.text.strip():
|
|
||||||
elem.text = i + " "
|
|
||||||
if not elem.tail or not elem.tail.strip():
|
|
||||||
elem.tail = i
|
|
||||||
for elem in elem:
|
|
||||||
indent(elem, level + 1)
|
|
||||||
if not elem.tail or not elem.tail.strip():
|
|
||||||
elem.tail = i
|
|
||||||
else:
|
|
||||||
if level and (not elem.tail or not elem.tail.strip()):
|
|
||||||
elem.tail = i
|
|
||||||
|
|
||||||
|
|
||||||
carrier_config_root = ET.Element('carrier_config_list')
|
|
||||||
|
|
||||||
with open('apns-full-conf.xml', 'w', encoding='utf-8') as f:
|
|
||||||
f.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n\n')
|
f.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n\n')
|
||||||
f.write('<apns version="8">\n\n')
|
f.write('<apns version="8">\n\n')
|
||||||
|
|
||||||
version_suffix = all_settings['default'].version % 1000000000
|
|
||||||
for entry in carrier_list.entry:
|
for entry in carrier_list.entry:
|
||||||
setting = all_settings[entry.canonicalName]
|
setting = all_settings[entry.canonicalName]
|
||||||
for apn in setting.apns.apn:
|
for apn in setting.apns.apn:
|
||||||
@@ -199,19 +214,6 @@ with open('apns-full-conf.xml', 'w', encoding='utf-8') as f:
|
|||||||
field,
|
field,
|
||||||
getattr(entry.carrierId, field),
|
getattr(entry.carrierId, field),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add version key composed of canonical name and versions
|
|
||||||
carrier_config_subelement = ET.SubElement(
|
|
||||||
carrier_config_element,
|
|
||||||
'string'
|
|
||||||
)
|
|
||||||
carrier_config_subelement.set('name', 'carrier_config_version_string')
|
|
||||||
carrier_config_subelement.text = '{}-{}.{}'.format(
|
|
||||||
setting.canonicalName,
|
|
||||||
setting.version,
|
|
||||||
version_suffix
|
|
||||||
)
|
|
||||||
|
|
||||||
for config in setting.configs.config:
|
for config in setting.configs.config:
|
||||||
value_type = config.WhichOneof('value')
|
value_type = config.WhichOneof('value')
|
||||||
if value_type == 'textValue':
|
if value_type == 'textValue':
|
||||||
@@ -288,10 +290,16 @@ with open('apns-full-conf.xml', 'w', encoding='utf-8') as f:
|
|||||||
|
|
||||||
f.write('</apns>\n')
|
f.write('</apns>\n')
|
||||||
|
|
||||||
indent(carrier_config_root)
|
# Test XML parsing.
|
||||||
carrier_config_tree = ET.ElementTree(carrier_config_root)
|
ET.parse(os.path.join(apns_folder, 'apns-conf.xml'))
|
||||||
carrier_config_tree.write('vendor.xml', encoding='utf-8', xml_declaration=True)
|
|
||||||
|
|
||||||
# Test XML parsing.
|
indent(carrier_config_root)
|
||||||
ET.parse('apns-full-conf.xml')
|
carrier_config_tree = ET.ElementTree(carrier_config_root)
|
||||||
ET.parse('vendor.xml')
|
carrier_config_tree.write(os.path.join(vendor_folder, 'vendor.xml'),
|
||||||
|
encoding='utf-8', xml_declaration=True)
|
||||||
|
|
||||||
|
# Test XML parsing.
|
||||||
|
ET.parse(os.path.join(vendor_folder, 'vendor.xml'))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user