Skip to content

Commit 3d99365

Browse files
committed
[checksum.py] adds support for checksum checks against file paths in a valid checksum files
1 parent a72e938 commit 3d99365

File tree

1 file changed

+67
-8
lines changed

1 file changed

+67
-8
lines changed

tools/scripts/checksum/checksum.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33

4-
#----------------------------------------------------------------
4+
#------------------------------------------------------------------------------------------------------
55
# checksum.py
66
# A SHA1 hash checksum list generator for fonts and fontTools
7-
# XML dumps of font OpenType table data
7+
# XML dumps of font OpenType table data + checksum testing
8+
# script
89
#
910
# Copyright 2018 Christopher Simpkins
1011
# MIT License
1112
#
13+
# Dependencies: Python fontTools library
14+
#
1215
# Usage: checksum.py (options) [file path 1]...[file path n]
1316
#
14-
# Dependencies: Python fontTools library
15-
#----------------------------------------------------------------
17+
# Options:
18+
# -h, --help Help
19+
# -t, --ttx Calculate SHA1 hash values from ttx dump of XML (default = font binary)
20+
# -s, --stdout Stream to standard output stream (default = write to disk as 'checksum.txt')
21+
# -c, --check Test SHA1 checksum values against a valid checksum file
22+
#
23+
# Options, --ttx only:
24+
# -e, --exclude Excluded OpenType table (may be used more than once, mutually exclusive with -i)
25+
# -i, --include Included OpenType table (may be used more than once, mutually exclusive with -e)
26+
# -n, --noclean Do not discard .ttx files that are used to calculate SHA1 hashes
27+
#-------------------------------------------------------------------------------------------------------
1628

1729
import argparse
1830
import hashlib
@@ -24,7 +36,7 @@
2436
from fontTools.ttLib import TTFont
2537

2638

27-
def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, exclude_tables=None, do_not_cleanup=False):
39+
def write_checksum(filepaths, stdout_write=False, use_ttx=False, include_tables=None, exclude_tables=None, do_not_cleanup=False):
2840
checksum_dict = {}
2941
for path in filepaths:
3042
if not os.path.exists(path):
@@ -42,6 +54,8 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
4254
temp_ttx_path = path + ".ttx"
4355

4456
tt = TTFont(path)
57+
# important to keep the newlinestr value defined here as hash values will change across platforms
58+
# if platform specific newline values are assumed
4559
tt.saveXML(temp_ttx_path, newlinestr="\n", skipTables=exclude_tables, tables=include_tables)
4660
checksum_path = temp_ttx_path
4761
else:
@@ -55,7 +69,7 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
5569
sys.exit(1)
5670
checksum_path = path
5771

58-
file_contents = read_binary(checksum_path)
72+
file_contents = _read_binary(checksum_path)
5973

6074
# store SHA1 hash data and associated file path basename in the checksum_dict dictionary
6175
checksum_dict[basename(checksum_path)] = hashlib.sha1(file_contents).hexdigest()
@@ -78,7 +92,48 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
7892
file.write(checksum_out_data)
7993

8094

81-
def read_binary(filepath):
95+
def check_checksum(filepaths):
96+
check_failed = False
97+
for path in filepaths:
98+
if not os.path.exists(path):
99+
sys.stderr.write("[checksum.py] ERROR: " + filepath + " is not a valid filepath" + os.linesep)
100+
sys.exit(1)
101+
102+
with open(path, mode='r') as file:
103+
for line in file.readlines():
104+
cleaned_line = line.rstrip()
105+
line_list = cleaned_line.split(" ")
106+
# eliminate empty strings parsed from > 1 space characters
107+
line_list = list(filter(None, line_list))
108+
if len(line_list) == 2:
109+
expected_sha1 = line_list[0]
110+
test_path = line_list[1]
111+
else:
112+
sys.stderr.write("[checksum.py] ERROR: failed to parse checksum file values" + os.linesep)
113+
sys.exit(1)
114+
115+
if not os.path.exists(test_path):
116+
print(test_path + ": Filepath is not valid, ignored")
117+
else:
118+
file_contents = _read_binary(test_path)
119+
observed_sha1 = hashlib.sha1(file_contents).hexdigest()
120+
if observed_sha1 == expected_sha1:
121+
print(test_path + ": OK")
122+
else:
123+
print("-" * 80)
124+
print(test_path + ": === FAIL ===")
125+
print("Expected vs. Observed:")
126+
print(expected_sha1)
127+
print(observed_sha1)
128+
print("-" * 80)
129+
check_failed = True
130+
131+
# exit with status code 1 if any fails detected across all tests in the check
132+
if check_failed is True:
133+
sys.exit(1)
134+
135+
136+
def _read_binary(filepath):
82137
with open(filepath, mode='rb') as file:
83138
return file.read()
84139

@@ -88,11 +143,15 @@ def read_binary(filepath):
88143
parser.add_argument("-t", "--ttx", help="Calculate from ttx file", action="store_true")
89144
parser.add_argument("-s", "--stdout", help="Write output to stdout stream", action="store_true")
90145
parser.add_argument("-n", "--noclean", help="Do not discard *.ttx files used to calculate SHA1 hashes", action="store_true")
146+
parser.add_argument("-c", "--check", help="Verify checksum values vs. files", action="store_true")
91147
parser.add_argument("filepaths", nargs="+", help="One or more file paths to font binary files")
92148

93149
parser.add_argument("-i", "--include", action="append", help="Included OpenType tables for ttx data dump")
94150
parser.add_argument("-e", "--exclude", action="append", help="Excluded OpenType tables for ttx data dump")
95151

96152
args = parser.parse_args(sys.argv[1:])
97153

98-
main(args.filepaths, stdout_write=args.stdout, use_ttx=args.ttx, do_not_cleanup=args.noclean, include_tables=args.include, exclude_tables=args.exclude)
154+
if args.check is True:
155+
check_checksum(args.filepaths)
156+
else:
157+
write_checksum(args.filepaths, stdout_write=args.stdout, use_ttx=args.ttx, do_not_cleanup=args.noclean, include_tables=args.include, exclude_tables=args.exclude)

0 commit comments

Comments
 (0)