pebble/tools/upload_lang_pack.py
2025-01-27 11:38:16 -08:00

237 lines
7.3 KiB
Python

# Copyright 2024 Google LLC
#
# 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.
import argparse
import logging
import os
import pbpack
import polib
import requests
import sys
import tempfile
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True
LP_URLS = {"staging": "https://lang-packs-staging.getpebble.com",
"production": "https://lp.getpebble.com"}
lp_url = None
if 'LP_HTTP_USERNAME' not in os.environ or 'LP_HTTP_PASSWORD' not in os.environ:
print """Missing HTTP username/password!
Please define LP_HTTP_USERNAME and LP_HTTP_PASSWORD in your environment"""
sys.exit(1)
lp_http_username = os.environ['LP_HTTP_USERNAME']
lp_http_password = os.environ['LP_HTTP_PASSWORD']
lp_auth = requests.auth.HTTPBasicAuth(lp_http_username, lp_http_password)
FIRMWARE_VERSION_TO_UPDATE = 4
def assert_ok(response):
if response.status_code != requests.codes.ok:
print response.status_code
print response.text
def find_existing_pack(hardware, lang):
# Look for an existing language pack. Use X.99.99 as the requesting version as the
# lp server will only return packs that are for the same major version and a smaller
# minor version, and we want the most recent pack with the highest minor version there is.
r = requests.get('{}/v1/languages'.format(lp_url),
params={'hardware': hardware,
'firmware': '{}.99.99'.format(FIRMWARE_VERSION_TO_UPDATE)},
auth=lp_auth)
assert_ok(r)
for l in r.json()['languages']:
if l['ISOLocal'] == lang:
return l
return None
def create_new_pack_json(hardware, name, fw_version, metadata):
return {
'name': name,
'localName': metadata['Name'],
'hardware': hardware,
'ISOLocal': metadata['Language'],
'firmware': fw_version,
'mobile': {
'name': 'ios',
'version': '2.6.0'
}
}
def pack_json_to_post_data(j):
# The POST data that the form wants looks like the following...
#
# pack[file]:https://language-packs-staging.s3.amazonaws.com/3TRBOAT-en_US.pbl
# pack[name]:English
# pack[localName]:English
# pack[hardware]:bb2
# pack[ISOLocal]:en_US
# pack[version]:1
# pack[firmware]:2.9.0
# pack[mobile][name]:ios
# pack[mobile][version]:2.6.0
#
# Convert our json into that form
fields = ('file', 'name', 'localName', 'hardware', 'ISOLocal', 'version', 'firmware')
d = {'pack[{}]'.format(f): j[f] for f in fields}
d['pack[mobile][name]'] = j['mobile']['name']
d['pack[mobile][version]'] = j['mobile']['version']
return d
def get_lang_metadata(lang_pack):
mo_filename = None
# Open up the lang_pack as a pbpack. The first entry is the STRINGS values, which is a mo
# file. Write this mo file out to a temporary file and use polib to parse out the metadata.
#
# The resulting dictionary will look something like the following...
#
# {u'Content-Transfer-Encoding': u'8bit',
# u'Content-Type': u'text/plain; charset=UTF-8',
# u'Language': u'fr_FR',
# u'MIME-Version': u'1.0',
# u'Name': u'Fran\xe7ais',
# u'POT-Creation-Date': u'2016-06-28 15:24-0400',
# u'Project-Id-Version': u'33.0',
# u'Report-Msgid-Bugs-To': u'',
# u'X-Generator': u'POEditor.com'}
try:
with open(lang_pack, 'rb') as f:
pack = pbpack.ResourcePack.deserialize(f, is_system=False)
with tempfile.NamedTemporaryFile(delete=False) as mo_file:
mo_filename = mo_file.name
# RESOURCE_ID_STRINGS is the 0th resource in the pb pack. Grab the data and write
# it to a file.
content_index = pack.table_entries[0].content_index
if len(pack.contents[content_index]) == 0:
# Assume this is an english pack
return {u'Language': u'en_US',
u'Name': u'English',
u'Project-Id-Version': u'1.0'}
mo_file.write(pack.contents[content_index])
mo_object = polib.mofile(mo_filename)
finally:
os.remove(mo_filename)
metadata = mo_object.metadata
# Validate the version field just to be sure
assert 'Project-Id-Version' in metadata
version_parts = metadata['Project-Id-Version'].split('.')
assert len(version_parts) == 2
int(version_parts[0]) # Just make sure it can be converted to a valid integer
return metadata
def upload_pack_to_s3(lang_pack):
r = requests.get('{}/admin/packs/sign'.format(lp_url),
params={'type': '', 'name': os.path.basename(lang_pack)},
auth=lp_auth)
assert_ok(r)
s3_upload_info = r.json()
with open(lang_pack, 'rb') as f:
r = requests.put(s3_upload_info['signed'], f)
assert_ok(r)
return s3_upload_info['url']
def post_edit_to_lp(pack_json):
post_data = pack_json_to_post_data(pack_json)
r = requests.post('{}/admin/packs/{}/edit'.format(lp_url, pack_json['id']),
data=post_data,
auth=lp_auth)
assert_ok(r)
def create_new_pack_on_lp(pack_json):
post_data = pack_json_to_post_data(pack_json)
r = requests.post('{}/admin/packs/add'.format(lp_url),
data=post_data,
auth=lp_auth)
assert_ok(r)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('hardware')
parser.add_argument('lang_pack')
parser.add_argument('--production', action='store_true')
parser.add_argument('--allow_new', action='store_true')
parser.add_argument('--name', default=None)
parser.add_argument('--fw_version', default='4.0.0')
args = parser.parse_args()
global lp_url
if args.production:
lp_url = LP_URLS["production"]
else:
lp_url = LP_URLS["staging"]
metadata = get_lang_metadata(args.lang_pack)
is_new = False
pack_json = find_existing_pack(args.hardware, metadata['Language'])
if pack_json is None:
if not args.allow_new:
print "No existing pack found"
return 1
if args.name is None:
print "Name is required for new packs"
return 1
pack_json = create_new_pack_json(args.hardware, args.name, args.fw_version, metadata)
is_new = True
# Update the pack with the new information
pack_json['version'] = metadata['Project-Id-Version'].split('.')[0]
pack_json['file'] = upload_pack_to_s3(args.lang_pack)
if is_new:
create_new_pack_on_lp(pack_json)
else:
post_edit_to_lp(pack_json)
if __name__ == '__main__':
main()