xref: /aosp_15_r20/external/fonttools/MetaTools/roundTrip.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughes#! /usr/bin/env python3
2*e1fe3e4aSElliott Hughes
3*e1fe3e4aSElliott Hughes"""usage: ttroundtrip [options] font1 ... fontN
4*e1fe3e4aSElliott Hughes
5*e1fe3e4aSElliott Hughes    Dump each TT/OT font as a TTX file, compile again to TTF or OTF
6*e1fe3e4aSElliott Hughes    and dump again. Then do a diff on the two TTX files. Append problems
7*e1fe3e4aSElliott Hughes    and diffs to a file called "report.txt" in the current directory.
8*e1fe3e4aSElliott Hughes    This is only for testing FontTools/TTX, the resulting files are
9*e1fe3e4aSElliott Hughes    deleted afterwards.
10*e1fe3e4aSElliott Hughes
11*e1fe3e4aSElliott Hughes    This tool supports some of ttx's command line options (-i, -t
12*e1fe3e4aSElliott Hughes    and -x). Specifying -t or -x implies ttx -m <originalfile> on
13*e1fe3e4aSElliott Hughes    the way back.
14*e1fe3e4aSElliott Hughes"""
15*e1fe3e4aSElliott Hughes
16*e1fe3e4aSElliott Hughes
17*e1fe3e4aSElliott Hughesimport sys
18*e1fe3e4aSElliott Hughesimport os
19*e1fe3e4aSElliott Hughesimport tempfile
20*e1fe3e4aSElliott Hughesimport getopt
21*e1fe3e4aSElliott Hughesimport traceback
22*e1fe3e4aSElliott Hughesfrom fontTools import ttx
23*e1fe3e4aSElliott Hughes
24*e1fe3e4aSElliott Hughes
25*e1fe3e4aSElliott Hughesclass Error(Exception):
26*e1fe3e4aSElliott Hughes    pass
27*e1fe3e4aSElliott Hughes
28*e1fe3e4aSElliott Hughes
29*e1fe3e4aSElliott Hughesdef usage():
30*e1fe3e4aSElliott Hughes    print(__doc__)
31*e1fe3e4aSElliott Hughes    sys.exit(2)
32*e1fe3e4aSElliott Hughes
33*e1fe3e4aSElliott Hughes
34*e1fe3e4aSElliott Hughesdef roundTrip(ttFile1, options, report):
35*e1fe3e4aSElliott Hughes    fn = os.path.basename(ttFile1)
36*e1fe3e4aSElliott Hughes    xmlFile1 = tempfile.mkstemp(".%s.ttx1" % fn)
37*e1fe3e4aSElliott Hughes    ttFile2 = tempfile.mkstemp(".%s" % fn)
38*e1fe3e4aSElliott Hughes    xmlFile2 = tempfile.mkstemp(".%s.ttx2" % fn)
39*e1fe3e4aSElliott Hughes
40*e1fe3e4aSElliott Hughes    try:
41*e1fe3e4aSElliott Hughes        ttx.ttDump(ttFile1, xmlFile1, options)
42*e1fe3e4aSElliott Hughes        if options.onlyTables or options.skipTables:
43*e1fe3e4aSElliott Hughes            options.mergeFile = ttFile1
44*e1fe3e4aSElliott Hughes        ttx.ttCompile(xmlFile1, ttFile2, options)
45*e1fe3e4aSElliott Hughes        options.mergeFile = None
46*e1fe3e4aSElliott Hughes        ttx.ttDump(ttFile2, xmlFile2, options)
47*e1fe3e4aSElliott Hughes
48*e1fe3e4aSElliott Hughes        diffcmd = 'diff -U2 -I ".*modified value\|checkSumAdjustment.*" "%s" "%s"' % (
49*e1fe3e4aSElliott Hughes            xmlFile1,
50*e1fe3e4aSElliott Hughes            xmlFile2,
51*e1fe3e4aSElliott Hughes        )
52*e1fe3e4aSElliott Hughes        output = os.popen(diffcmd, "r", 1)
53*e1fe3e4aSElliott Hughes        lines = []
54*e1fe3e4aSElliott Hughes        while True:
55*e1fe3e4aSElliott Hughes            line = output.readline()
56*e1fe3e4aSElliott Hughes            if not line:
57*e1fe3e4aSElliott Hughes                break
58*e1fe3e4aSElliott Hughes            sys.stdout.write(line)
59*e1fe3e4aSElliott Hughes            lines.append(line)
60*e1fe3e4aSElliott Hughes        if lines:
61*e1fe3e4aSElliott Hughes            report.write(
62*e1fe3e4aSElliott Hughes                "=============================================================\n"
63*e1fe3e4aSElliott Hughes            )
64*e1fe3e4aSElliott Hughes            report.write('  "%s" differs after round tripping\n' % ttFile1)
65*e1fe3e4aSElliott Hughes            report.write(
66*e1fe3e4aSElliott Hughes                "-------------------------------------------------------------\n"
67*e1fe3e4aSElliott Hughes            )
68*e1fe3e4aSElliott Hughes            report.writelines(lines)
69*e1fe3e4aSElliott Hughes        else:
70*e1fe3e4aSElliott Hughes            print("(TTX files are the same)")
71*e1fe3e4aSElliott Hughes    finally:
72*e1fe3e4aSElliott Hughes        for tmpFile in (xmlFile1, ttFile2, xmlFile2):
73*e1fe3e4aSElliott Hughes            if os.path.exists(tmpFile):
74*e1fe3e4aSElliott Hughes                os.remove(tmpFile)
75*e1fe3e4aSElliott Hughes
76*e1fe3e4aSElliott Hughes
77*e1fe3e4aSElliott Hughesdef main(args):
78*e1fe3e4aSElliott Hughes    try:
79*e1fe3e4aSElliott Hughes        rawOptions, files = getopt.getopt(args, "it:x:")
80*e1fe3e4aSElliott Hughes    except getopt.GetoptError:
81*e1fe3e4aSElliott Hughes        usage()
82*e1fe3e4aSElliott Hughes
83*e1fe3e4aSElliott Hughes    if not files:
84*e1fe3e4aSElliott Hughes        usage()
85*e1fe3e4aSElliott Hughes
86*e1fe3e4aSElliott Hughes    with open("report.txt", "a+") as report:
87*e1fe3e4aSElliott Hughes        options = ttx.Options(rawOptions, len(files))
88*e1fe3e4aSElliott Hughes        for ttFile in files:
89*e1fe3e4aSElliott Hughes            try:
90*e1fe3e4aSElliott Hughes                roundTrip(ttFile, options, report)
91*e1fe3e4aSElliott Hughes            except KeyboardInterrupt:
92*e1fe3e4aSElliott Hughes                print("(Cancelled)")
93*e1fe3e4aSElliott Hughes                break
94*e1fe3e4aSElliott Hughes            except:
95*e1fe3e4aSElliott Hughes                print("*** round tripping aborted ***")
96*e1fe3e4aSElliott Hughes                traceback.print_exc()
97*e1fe3e4aSElliott Hughes                report.write(
98*e1fe3e4aSElliott Hughes                    "=============================================================\n"
99*e1fe3e4aSElliott Hughes                )
100*e1fe3e4aSElliott Hughes                report.write("  An exception occurred while round tripping")
101*e1fe3e4aSElliott Hughes                report.write('  "%s"\n' % ttFile)
102*e1fe3e4aSElliott Hughes                traceback.print_exc(file=report)
103*e1fe3e4aSElliott Hughes                report.write(
104*e1fe3e4aSElliott Hughes                    "-------------------------------------------------------------\n"
105*e1fe3e4aSElliott Hughes                )
106*e1fe3e4aSElliott Hughes
107*e1fe3e4aSElliott Hughes
108*e1fe3e4aSElliott Hughesmain(sys.argv[1:])
109