Commit cb684ec4d3bdc68438f269b6cc611d6ba3ff6aa1
1 parent
fc14bfbb
QPDFJob increment: generate table names
Showing
4 changed files
with
76 additions
and
28 deletions
generate_auto_job
| ... | ... | @@ -4,6 +4,7 @@ import sys |
| 4 | 4 | import argparse |
| 5 | 5 | import hashlib |
| 6 | 6 | import re |
| 7 | +import yaml | |
| 7 | 8 | |
| 8 | 9 | whoami = os.path.basename(sys.argv[0]) |
| 9 | 10 | BANNER = f'''// |
| ... | ... | @@ -19,6 +20,9 @@ def warn(*args, **kwargs): |
| 19 | 20 | |
| 20 | 21 | class Main: |
| 21 | 22 | SOURCES = [whoami, 'job.yml'] |
| 23 | + DESTS = { | |
| 24 | + 'decl': 'libqpdf/qpdf/auto_job_decl.hh', | |
| 25 | + } | |
| 22 | 26 | SUMS = 'job.sums' |
| 23 | 27 | |
| 24 | 28 | def main(self, args=sys.argv[1:], prog=whoami): |
| ... | ... | @@ -49,11 +53,14 @@ class Main: |
| 49 | 53 | |
| 50 | 54 | def get_hashes(self): |
| 51 | 55 | hashes = {} |
| 52 | - for i in sorted(self.SOURCES): | |
| 56 | + for i in sorted([*self.SOURCES, *self.DESTS.values()]): | |
| 53 | 57 | m = hashlib.sha256() |
| 54 | - with open(i, 'rb') as f: | |
| 55 | - m.update(f.read()) | |
| 56 | - hashes[i] = m.hexdigest() | |
| 58 | + try: | |
| 59 | + with open(i, 'rb') as f: | |
| 60 | + m.update(f.read()) | |
| 61 | + hashes[i] = m.hexdigest() | |
| 62 | + except FileNotFoundError: | |
| 63 | + pass | |
| 57 | 64 | return hashes |
| 58 | 65 | |
| 59 | 66 | def check(self): |
| ... | ... | @@ -82,12 +89,51 @@ class Main: |
| 82 | 89 | def generate(self): |
| 83 | 90 | warn(f'{whoami}: regenerating auto job files') |
| 84 | 91 | |
| 85 | - with open('libqpdf/qpdf/auto_job_decl.hh', 'w') as f: | |
| 86 | - print(BANNER, file=f) | |
| 92 | + with open('job.yml', 'r') as f: | |
| 93 | + data = yaml.safe_load(f.read()) | |
| 94 | + self.validate(data) | |
| 95 | + self.generate_decl(data) | |
| 87 | 96 | |
| 88 | 97 | # Update hashes last to ensure that this will be rerun in the |
| 89 | 98 | # event of a failure. |
| 90 | 99 | self.update_hashes() |
| 100 | + # DON'T ADD CODE TO generate AFTER update_hashes | |
| 101 | + | |
| 102 | + def check_keys(self, what, d, exp): | |
| 103 | + if not isinstance(d, dict): | |
| 104 | + exit(f'{what} is not a dictionary') | |
| 105 | + actual = set(d.keys()) | |
| 106 | + extra = actual - exp | |
| 107 | + if extra: | |
| 108 | + exit(f'{what}: unknown keys = {extra}') | |
| 109 | + | |
| 110 | + def validate(self, data): | |
| 111 | + self.check_keys('top', data, set(['choices', 'options'])) | |
| 112 | + for o in data['options']: | |
| 113 | + self.check_keys('top', o, set( | |
| 114 | + ['table', 'bare', 'positional', | |
| 115 | + 'optional_parameter', 'required_parameter', | |
| 116 | + 'required_choices', 'from_table'])) | |
| 117 | + | |
| 118 | + def to_identifier(self, label, prefix, const): | |
| 119 | + identifier = re.sub(r'[^a-zA-Z0-9]', '_', label) | |
| 120 | + if const: | |
| 121 | + identifier = identifier.upper() | |
| 122 | + else: | |
| 123 | + identifier = identifier.lower() | |
| 124 | + identifier = re.sub('_([a-z])', lambda x: x.group(1).upper(), | |
| 125 | + identifier) | |
| 126 | + return prefix + identifier | |
| 127 | + | |
| 128 | + def generate_decl(self, data): | |
| 129 | + with open(self.DESTS['decl'], 'w') as f: | |
| 130 | + print(BANNER, file=f) | |
| 131 | + for o in data['options']: | |
| 132 | + table = o['table'] | |
| 133 | + if table in ('main', 'help'): | |
| 134 | + continue | |
| 135 | + i = self.to_identifier(table, 'O_', True) | |
| 136 | + print(f'static constexpr char const* {i} = "{table}";', file=f) | |
| 91 | 137 | |
| 92 | 138 | |
| 93 | 139 | if __name__ == '__main__': | ... | ... |
job.sums
| 1 | 1 | # Generated by generate_auto_job |
| 2 | -generate_auto_job 3905985c383d33f9e8629414d1481724ea67d836749f6dff53859ca558325743 | |
| 2 | +generate_auto_job e0cbb20dade91ebbab5907a53ba83ed3bb4b6cf4bfa75304a4b88e23906fbb6c | |
| 3 | 3 | job.yml 8c66b75eb06be65dfa40058a52cbc0bc18627a3aade5b3d4e034543605c93298 |
| 4 | +libqpdf/qpdf/auto_job_decl.hh b098ee02ec853f47850b6421cc72b08c608f303f74f01d0b3ce3df52cecd5ffa | ... | ... |
libqpdf/QPDFJob_argv.cc
| ... | ... | @@ -23,14 +23,7 @@ namespace |
| 23 | 23 | void parseOptions(); |
| 24 | 24 | |
| 25 | 25 | private: |
| 26 | - static constexpr char const* O_PAGES = "pages"; | |
| 27 | - static constexpr char const* O_ENCRYPT = "encryption"; | |
| 28 | - static constexpr char const* O_ENCRYPT_40 = "40-bit encryption"; | |
| 29 | - static constexpr char const* O_ENCRYPT_128 = "128-bit encryption"; | |
| 30 | - static constexpr char const* O_ENCRYPT_256 = "256-bit encryption"; | |
| 31 | - static constexpr char const* O_UNDER_OVERLAY = "underlay/overlay"; | |
| 32 | - static constexpr char const* O_ATTACHMENT = "attachment"; | |
| 33 | - static constexpr char const* O_COPY_ATTACHMENT = "copy attachment"; | |
| 26 | +# include <qpdf/auto_job_decl.hh> | |
| 34 | 27 | |
| 35 | 28 | void argHelp(); |
| 36 | 29 | void argVersion(); |
| ... | ... | @@ -344,16 +337,16 @@ ArgParser::initOptionTable() |
| 344 | 337 | |
| 345 | 338 | this->ap.selectMainOptionTable(); |
| 346 | 339 | this->ap.addBare("encrypt", b(&ArgParser::argEncrypt)); |
| 347 | - this->ap.registerOptionTable(O_ENCRYPT, b(&ArgParser::argEndEncrypt)); | |
| 340 | + this->ap.registerOptionTable(O_ENCRYPTION, b(&ArgParser::argEndEncrypt)); | |
| 348 | 341 | this->ap.addPositional(p(&ArgParser::argEncryptPositional)); |
| 349 | - this->ap.registerOptionTable(O_ENCRYPT_40, b(&ArgParser::argEndEncrypt)); | |
| 342 | + this->ap.registerOptionTable(O_40_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); | |
| 350 | 343 | this->ap.addRequiredChoices("extract",p(&ArgParser::arg40Extract), yn); |
| 351 | 344 | this->ap.addRequiredChoices("annotate",p(&ArgParser::arg40Annotate), yn); |
| 352 | 345 | this->ap.addRequiredChoices("print",p(&ArgParser::arg40Print), yn); |
| 353 | 346 | this->ap.addRequiredChoices("modify",p(&ArgParser::arg40Modify), yn); |
| 354 | - this->ap.registerOptionTable(O_ENCRYPT_128, b(&ArgParser::argEndEncrypt)); | |
| 355 | - this->ap.registerOptionTable(O_ENCRYPT_256, b(&ArgParser::argEndEncrypt)); | |
| 356 | - for (char const* k: {O_ENCRYPT_128, O_ENCRYPT_256}) | |
| 347 | + this->ap.registerOptionTable(O_128_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); | |
| 348 | + this->ap.registerOptionTable(O_256_BIT_ENCRYPTION, b(&ArgParser::argEndEncrypt)); | |
| 349 | + for (char const* k: {O_128_BIT_ENCRYPTION, O_256_BIT_ENCRYPTION}) | |
| 357 | 350 | { |
| 358 | 351 | this->ap.selectOptionTable(k); |
| 359 | 352 | this->ap.addRequiredChoices("accessibility", |
| ... | ... | @@ -373,15 +366,15 @@ ArgParser::initOptionTable() |
| 373 | 366 | this->ap.addBare("cleartext-metadata", b(&ArgParser::arg128ClearTextMetadata)); |
| 374 | 367 | } |
| 375 | 368 | |
| 376 | - this->ap.selectOptionTable(O_ENCRYPT_128); | |
| 369 | + this->ap.selectOptionTable(O_128_BIT_ENCRYPTION); | |
| 377 | 370 | this->ap.addRequiredChoices("use-aes",p(&ArgParser::arg128UseAes), yn); |
| 378 | 371 | this->ap.addBare("force-V4", b(&ArgParser::arg128ForceV4)); |
| 379 | 372 | |
| 380 | - this->ap.selectOptionTable(O_ENCRYPT_256); | |
| 373 | + this->ap.selectOptionTable(O_256_BIT_ENCRYPTION); | |
| 381 | 374 | this->ap.addBare("force-R5", b(&ArgParser::arg256ForceR5)); |
| 382 | 375 | this->ap.addBare("allow-insecure", b(&ArgParser::argAllowInsecure)); |
| 383 | 376 | |
| 384 | - this->ap.registerOptionTable(O_UNDER_OVERLAY, b(&ArgParser::argEndUnderOverlay)); | |
| 377 | + this->ap.registerOptionTable(O_UNDERLAY_OVERLAY, b(&ArgParser::argEndUnderOverlay)); | |
| 385 | 378 | this->ap.addPositional(p(&ArgParser::argUOpositional)); |
| 386 | 379 | this->ap.addRequiredParameter("to", |
| 387 | 380 | p(&ArgParser::argUOto), "page-range"); |
| ... | ... | @@ -1089,7 +1082,7 @@ ArgParser::argEncrypt() |
| 1089 | 1082 | { |
| 1090 | 1083 | this->ap.insertCompletion("user-password"); |
| 1091 | 1084 | } |
| 1092 | - this->ap.selectOptionTable(O_ENCRYPT); | |
| 1085 | + this->ap.selectOptionTable(O_ENCRYPTION); | |
| 1093 | 1086 | } |
| 1094 | 1087 | |
| 1095 | 1088 | void |
| ... | ... | @@ -1120,18 +1113,18 @@ ArgParser::argEncryptPositional(char* arg) |
| 1120 | 1113 | if (len_str == "40") |
| 1121 | 1114 | { |
| 1122 | 1115 | o.keylen = 40; |
| 1123 | - this->ap.selectOptionTable(O_ENCRYPT_40); | |
| 1116 | + this->ap.selectOptionTable(O_40_BIT_ENCRYPTION); | |
| 1124 | 1117 | } |
| 1125 | 1118 | else if (len_str == "128") |
| 1126 | 1119 | { |
| 1127 | 1120 | o.keylen = 128; |
| 1128 | - this->ap.selectOptionTable(O_ENCRYPT_128); | |
| 1121 | + this->ap.selectOptionTable(O_128_BIT_ENCRYPTION); | |
| 1129 | 1122 | } |
| 1130 | 1123 | else if (len_str == "256") |
| 1131 | 1124 | { |
| 1132 | 1125 | o.keylen = 256; |
| 1133 | 1126 | o.use_aes = true; |
| 1134 | - this->ap.selectOptionTable(O_ENCRYPT_256); | |
| 1127 | + this->ap.selectOptionTable(O_256_BIT_ENCRYPTION); | |
| 1135 | 1128 | } |
| 1136 | 1129 | else |
| 1137 | 1130 | { |
| ... | ... | @@ -2202,7 +2195,7 @@ void |
| 2202 | 2195 | ArgParser::parseUnderOverlayOptions(QPDFJob::UnderOverlay* uo) |
| 2203 | 2196 | { |
| 2204 | 2197 | o.under_overlay = uo; |
| 2205 | - this->ap.selectOptionTable(O_UNDER_OVERLAY); | |
| 2198 | + this->ap.selectOptionTable(O_UNDERLAY_OVERLAY); | |
| 2206 | 2199 | } |
| 2207 | 2200 | |
| 2208 | 2201 | void | ... | ... |
libqpdf/qpdf/auto_job_decl.hh
| ... | ... | @@ -3,3 +3,11 @@ |
| 3 | 3 | // Edits will be automatically overwritten if the build is |
| 4 | 4 | // run in maintainer mode. |
| 5 | 5 | // |
| 6 | +static constexpr char const* O_PAGES = "pages"; | |
| 7 | +static constexpr char const* O_ENCRYPTION = "encryption"; | |
| 8 | +static constexpr char const* O_40_BIT_ENCRYPTION = "40-bit encryption"; | |
| 9 | +static constexpr char const* O_128_BIT_ENCRYPTION = "128-bit encryption"; | |
| 10 | +static constexpr char const* O_256_BIT_ENCRYPTION = "256-bit encryption"; | |
| 11 | +static constexpr char const* O_UNDERLAY_OVERLAY = "underlay/overlay"; | |
| 12 | +static constexpr char const* O_ATTACHMENT = "attachment"; | |
| 13 | +static constexpr char const* O_COPY_ATTACHMENT = "copy attachment"; | ... | ... |