Add tool for updating the version info in the color emoji template.
Right now we do this by hand. This makes it possible to do this automatically. It also adds information to the nametable version string about the commit the font was built from.pull/130/head
parent
aedda3111b
commit
c853b95987
|
@ -0,0 +1,192 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2015 Google Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Generate version string for NotoColorEmoji.
|
||||
|
||||
This parses the color emoji template file and updates the lines
|
||||
containing version string info, writing a new file.
|
||||
|
||||
The nameID 5 field in the emoji font should reflect the commit/date
|
||||
of the repo it was built from. This will build a string of the following
|
||||
format:
|
||||
Version 1.39;GOOG;noto-emoji:20170220:a8a215d2e889'
|
||||
|
||||
This is intended to indicate that it was built by Google from noto-emoji
|
||||
at commit a8a215d2e889 and date 20170220 (since dates are a bit easier
|
||||
to locate in time than commit hashes).
|
||||
|
||||
For building with external data we don't include the commit id as we
|
||||
might be using different resoruces. Instead the version string is:
|
||||
Version 1.39;GOOG;noto-emoji:20170518;BETA <msg>
|
||||
|
||||
Here the date is the current date, and the message after 'BETA ' is
|
||||
provided using the '-b' flag. There's no commit hash. This also
|
||||
bypasses some checks about the state of the repo.
|
||||
|
||||
The relase number should have 2 or 3 minor digits. Right now we've been
|
||||
using 2 but at the next major relase we probably want to use 3. This
|
||||
supports both. It will bump the version number if none is provided,
|
||||
maintaining the minor digit length.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import re
|
||||
|
||||
from nototools import tool_utils
|
||||
|
||||
# These are not very lenient, we expect to be applied to the noto color
|
||||
# emoji template ttx file which matches these. Why then require the
|
||||
# input argument, you ask? Um... testing?
|
||||
_nameid_re = re.compile(r'\s*<namerecord nameID="5"')
|
||||
_version_re = re.compile(r'\s*Version\s(\d+.\d{2,3})')
|
||||
_headrev_re = re.compile(r'\s*<fontRevision value="(\d+.\d{2,3})"/>')
|
||||
|
||||
def _get_existing_version(lines):
|
||||
"""Scan lines for all existing version numbers, and ensure they match.
|
||||
Return the matched version number string."""
|
||||
|
||||
version = None
|
||||
def check_version(new_version):
|
||||
if version is not None and new_version != version:
|
||||
raise Exception(
|
||||
'version %s and namerecord version %s do not match' % (
|
||||
version, new_version))
|
||||
return new_version
|
||||
|
||||
saw_nameid = False
|
||||
for line in lines:
|
||||
if saw_nameid:
|
||||
saw_nameid = False
|
||||
m = _version_re.match(line)
|
||||
if not m:
|
||||
raise Exception('could not match line "%s" in namerecord' % line)
|
||||
version = check_version(m.group(1))
|
||||
elif _nameid_re.match(line):
|
||||
saw_nameid = True
|
||||
else:
|
||||
m = _headrev_re.match(line)
|
||||
if m:
|
||||
version = check_version(m.group(1))
|
||||
return version
|
||||
|
||||
|
||||
def _version_to_mm(version):
|
||||
majs, mins = version.split('.')
|
||||
minor_len = len(mins)
|
||||
return int(majs), int(mins), minor_len
|
||||
|
||||
|
||||
def _mm_to_version(major, minor, minor_len):
|
||||
fmt = '%%d.%%0%dd' % minor_len
|
||||
return fmt % (major, minor)
|
||||
|
||||
|
||||
def _version_compare(lhs, rhs):
|
||||
lmaj, lmin, llen = _version_to_mm(lhs)
|
||||
rmaj, rmin, rlen = _version_to_mm(rhs)
|
||||
# if major versions differ, we don't care about the minor length, else
|
||||
# they should be the same
|
||||
if lmaj != rmaj:
|
||||
return lmaj - rmaj
|
||||
if llen != rlen:
|
||||
raise Exception('minor version lengths differ: "%s" and "%s"' % (lhs, rhs))
|
||||
return lmin - rmin
|
||||
|
||||
|
||||
def _version_bump(version):
|
||||
major, minor, minor_len = _version_to_mm(version)
|
||||
minor = (minor + 1) % (10 ** minor_len)
|
||||
if minor == 0:
|
||||
raise Exception('cannot bump version "%s", requires new major' % version)
|
||||
return _mm_to_version(major, minor, minor_len)
|
||||
|
||||
|
||||
def _get_repo_version_str(beta):
|
||||
"""See above for description of this string."""
|
||||
if beta is not None:
|
||||
date_str = datetime.date.today().strftime('%Y%m%d')
|
||||
return 'GOOG;noto-emoji:%s;BETA %s' % (date_str, beta)
|
||||
|
||||
p = tool_utils.resolve_path('[emoji]')
|
||||
commit, date, _ = tool_utils.git_head_commit(p)
|
||||
if not tool_utils.git_check_remote_commit(p, commit):
|
||||
raise Exception('emoji not on upstream master branch')
|
||||
date_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})')
|
||||
m = date_re.match(date)
|
||||
if not m:
|
||||
raise Exception('could not match "%s" with "%s"' % (date, date_re.pattern))
|
||||
ymd = ''.join(m.groups())
|
||||
return 'GOOG;noto-emoji:%s:%s' % (ymd, commit[:12])
|
||||
|
||||
|
||||
def _replace_existing_version(lines, version, version_str):
|
||||
"""Update lines with new version strings in appropriate places."""
|
||||
saw_nameid = False
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if saw_nameid:
|
||||
saw_nameid = False
|
||||
# preserve indentation
|
||||
lead_ws = len(line) - len(line.lstrip())
|
||||
lines[i] = line[:lead_ws] + version_str + '\n'
|
||||
elif _nameid_re.match(line):
|
||||
saw_nameid = True
|
||||
elif _headrev_re.match(line):
|
||||
lead_ws = len(line) - len(line.lstrip())
|
||||
lines[i] = line[:lead_ws] + '<fontRevision value="%s"/>\n' % version
|
||||
|
||||
|
||||
def update_version(srcfile, dstfile, version, beta):
|
||||
"""Update version in srcfile and write to dstfile. If version is None,
|
||||
bumps the current version, else version must be greater than the
|
||||
current verison."""
|
||||
|
||||
with open(srcfile, 'r') as f:
|
||||
lines = f.readlines()
|
||||
current_version = _get_existing_version(lines)
|
||||
if not version:
|
||||
version = _version_bump(current_version)
|
||||
elif version and _version_compare(version, current_version) <= 0:
|
||||
raise Exception('new version %s is <= current version %s' % (
|
||||
version, current_version))
|
||||
version_str = 'Version %s;%s' % (version, _get_repo_version_str(beta))
|
||||
_replace_existing_version(lines, version, version_str)
|
||||
with open(dstfile, 'w') as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-v', '--version', help='version number, default bumps the current '
|
||||
'version', metavar='ver')
|
||||
parser.add_argument(
|
||||
'-s', '--src', help='ttx file with name and head tables',
|
||||
metavar='file', required=True)
|
||||
parser.add_argument(
|
||||
'-d', '--dst', help='name of edited ttx file to write',
|
||||
metavar='file', required=True)
|
||||
parser.add_argument(
|
||||
'-b', '--beta', help='beta tag if font is built using external resources')
|
||||
args = parser.parse_args()
|
||||
|
||||
update_version(args.src, args.dst, args.version, args.beta)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue